CISC4080, Computer Algorithms,
Lab 3

     

Home

Schedule

Assignments

Grading

 

Goal:

  1. Practice implementing heap (as a data structure)
  2. Understand application of heap: priority queue and heapsort

Overview:

A heap is a complete binary tree stored in an array, and elements stored in nodes satisfy heap property (for every node in the heap, the key of the element stored in the node is smaller than the element stored in its parent). The elements of the tree is stored in an array in a depth-first, left-to-right order. Therefore root node is stored at the first location of array, it's left child next, followed by its right child, and so on and on. We refer to a node in the tree using the index, so node 1 is the root node, and node 4 is the left child of root's left child. The internal data members of a heap should be (assuming the heap stores ItemType values) just an array and a length field.

After implementing and testing the heap data structure, you will use heap to implement a PriorityQueue, see below for details. We implement the so called max-priority queue, where items with largest key value are accessed and returned first.

Details:

  1. Implement heap data structure as a template class, please follow exactly the header file.
    • Below gives a suggestion about private data members and methods for the class.
      /* Note the type ItemType needs to implement comparison operators */
      const int MAX_SIZE 100;
      template <class ItemType> 
      class Heap{
      public:
          //set heap size to be zero
          Heap();
      
          //Initialize the heap with the given data, and call build_heap to make it a heap
          Heap(ItemType initData[], int len);
      
          //return true if heap property is satisfied, false if violated 
          bool IsHeap(); 
      
          //Additional public methods described below
      
      private:
           //precondition: i is the numbering of node (starting from 1)
           //              i is not 1 (as root node has no parent) 
           //postcondition: the numbering of node i's parent is returned 
           int parent(int i);     //return i/2 (calculating i/2 using bitewise shift operators)
      
           //return the numbering of the left child of node i 
           // if node i has no left child, return -1 (note use heapLength to see if there is one) 
           int leftchild (int i); //return 2*i (calculated using bitwise shift operators) 
      
           //return the numbering of the right child of node i 
           // if node i has no right child, return -1 (note use heapLength to see if there is one) 
           int rightchild (int i); // return 2*i+1 (left shift, bitwise OR)
      
           ItemType data[MAX_SIZE];  //You could store elements from index 1 (i.e., leave
           	//first slot of the array empty), this way, you can use abvoe parent(),leftchild(), 
      	//rightchild() function to return the location of the nodes
           int heapLength;   // the actual number of elements in the heap 
      };
      
    • Required methods: Implement the following methods for Heap class (feel free to introduce additional methods as necessary):
      1. heapify(i): assuming node i's left subtree and right subtree meet the heap property, but node i might violate heap property, this operation fixes this subtree rooted at node i, so that this subtree is a heap. Here are a list of occasions when heapify needs to be called to fix the heap:
        • When node i's value is changed to a smaller value, then heapify(i) can fix the whole heap.
        • Note that if node i's value is changed to a larger value, then the tree rooted at i is still a heap, but the whole tree might not (If node i's new value is larger than it's parent, then we need to call heapify() on node i's parent).
        • Used in build_heap() operation, where we call heapify() on all non-leaf nodes, starting from nodes at the lower level, and working our way to the root node.
      2. build_heap(): assuming the array has been filled with elements, but heap property is not satisfied, this methods rearrange elements so that the whole heap statisfies heap property. This method should be called in the second constructor, Heap(ItemType initData[]).
      3. Insert(ItemType item): insert a new item into the heap. In order to maintain the heap property, the following pseudocode outlines how to insert an new item:
        	1. increment heap length by 1
        	2. store new item at the end of the heap, say the location is j
        	3. walk your way up from node j to root, compare values stored at a node with its parent and swap
        	  the items if necessary. 
        	
      4. void Modify(int i, ItemType newValue): modify item stored in position i to the newValue, and repair heap property. (Note that you cannot just call build_heap, which is overkill, instead you need to repair heap property as efficient as possible).
      5. ItemType GetRoot(); return the item stored in the root node of the heap
      6. ItemType RemoveRoot(); remove and return item stored in root from the heap
  2. Using the heap class to implement heapsort function in main, and test it:
    	/* arrange values in array a in ascending order
    	   param a: the array
    	   param size: the length of array (# of element)
    	  */
    	void heapsort(int a[], int size)
    	{
    		heap<int> heapInt(a, size);
    		... //see slides for pseudocide 
    	}
    	
  3. In your driver program (main()), test your heap class as follows. You can use the given code as starting point:
       First test Heap class 
       1. Initialize a heap with an array of elements 
       2. Test if heap property is satisfied 
       3. Test Insert, Modify, and RemoveRoot, ... methods 
       4. Test heapsort funciton 
    
Additional Resources

You can practice some performance enhancement details in this lab:

  1. Use bitwise operators to perform operations such as dividing an integer by 2, multiplying an integer by 2, or multiplying by 2 and then adding one.
  2. Use inline function to avoid function call overhead: compiler will replace the function call with the actual function body code. You can inline parent(), leftchild(), rightchild() functions, for example.

What to submit

Please submit all your source codes (.cc, .cpp, .h) one by one. For example, if you have two .cpp files (lab1_main.cpp and sorting.cpp), do the following:

	submit4080 LAB3 heaplab.cpp