Notes on Heaps

(related reading: Main & Savitch, pp. 492-499)

Building a better priority queue

The heap-order property

The key of each node is greater than the keys of its descendants.
       (9)
      /   \
    (7)   (3)
    / \     \
  (5) (6)   (1)
  /
(2)

Heaps

A heap is a tree with the heap-order property and such that: In other words, new nodes are added from left to right, from top to bottom.
  (not a heap)                      (heap)

       (9)                            (9)     
      /   \    		             /   \    
    (7)   (3)  		          (7)     (3)  
    /       \  		          / \     /
  (5)       (1)		        (5) (2) (1)
  /            		      
(2)
A heap that is a binary tree is known as a binary-heap.

Complete binary trees

A binary tree is completely full if every non-leaf node has exactly two children and all the leaves are at the same depth.
      (8)
     /   \
  (4)     (6)
  / \     / \
(3) (1) (5) (7)
A binary tree is complete if each non-leaf node has all its children except for at most one which is the deepest, rightmost non-leaf node.
      (8)                   (8)       
     /   \      	   /   \      
  (4)     (6)  	         (4)   (6)  
  / \     /    	         / 
(3) (1) (5)    	       (3) 

Heap operations

Operations on heaps are just like those on priority queues:

maximum

The heap-order property implies that the item with maximum key must be stored at the root. So maximum can simply return the item at root.

insert

  1. Add a new node at next open position in the complete tree.
  2. Copy the item/key into that node.
  3. If new node's key is greater than its parent's, swap, and repeat considering the parent node until heap-order property is reestablished.

extractMax

  1. Save item at root.
  2. Move contents of last (bottommost, rightmost) node to root.
  3. Swap that item/key with the child that has the greater key.
  4. Repeat previous step until heap-order property is reestablished.
  5. Return the item originally at root.

Implementing heaps

  • Binary trees --- easy, except, how do we find "next available space in the tree?" There are ways to do this in O(lg(n)), but we can do it in O(1) using arrays.


  • Arrays --- not efficient for trees in general, but very efficient for complete binary trees.
  • Suppose heap is an array representing a heap. An example of a priority queue using array-based binary heaps can be found here. Below is part of the declaration of such a priority queue:
    template <class Item, class Key>
    class PQueue {
    public:
      ...
      Item maximum() const;
      void insert(const Item& it, const Key& priority);
      Item extractMax();
      ...
    private:
      ...
      typedef IKPair IKP;
      static const size_t INITIAL_CAPACITY = 2;
      IKP *heap; // dynamic array
      size_t count; 
      size_t capacity; // size of current dynamic array
    
      // Helper functions:		     
      size_t parent(size_t index) const;
      size_t left(size_t index) const;
      size_t right(size_t index) const;
      bool hasLeft(size_t index) const;
      bool hasRight(size_t index) const;
      void heapifyDown(size_t index);
      void heapifyUp(size_t index);
    };
    

    Faster sorting

    Both insert and extractMax, for a priority queue using heap, have worst-case run-time complexity of O(lg(n)) since the tree is always complete. This means that sorting with a heap-base priority queue can be done in O(n(lg(n)) the fastest sorting algorithm we've seen yet. This sort is known as heapsort.