Heaps and HeapSort

A heap is a binary tree that satisfies these special SHAPE and ORDER properties:

  • Its shape must be a complete binary tree.
  • For each node in the heap, the value stored in that node is greater than or equal to the value in each of its children.

Which are Heaps?

          

  (no)                                                                                                (yes)

Use of Heaps

  • heaps have special properties that can make certain kinds of operations on stored data more efficient
  • Question: where is the largest element in a heap always stored?

Node Ordering in a Heap (for array implementation)

do by ordering across levels starting at the top

Can now store elements using this ordering

Some Notes:

  • Parent of node i is stored at array location: floor(i/2)
  • Left child of node i is stored at array location: 2i
  • Right child of node i is stored at array location: 2i + 1

Heap Operations

  • Heapify Operation that insures that a heap stays a heap
  • Build-heap Converts an unordered array into a heap.
  • Heapsort Using the array storing the heap sorts the array in place.

Heapify

This procedure is used by the heapsort. It assumes that the values in the array are almost a heap. It is only the root that may be violating the heap principle (the left and right child of the root are assumed to be heaps).

Used to insert new element in the heap

//pseudo-code


Heapify(int A[], int current)   
{  if left(current) <= A.heapsize() and A[left(current)] > A[current] 
    largest = left(current)
  else
    largest = current


  if right(current) <= A.heapsize() and A[right(current)] > A[largest] 
    largest = right(current)
  

  if largest != current 
    swap(A[largest], A[current]
    Heapify(A, largest)
 } 

int left(int index) 
  return 2 * index

int right(int index) 
  return 2 * index + 1

int parent(int index) 
  return index / 2

Running Time of Heapify

What is the running time of Heapify?

Heapify is recursive so we will create a 
recurrence relation to express the running time:

The running time of the algorithm without the 
recursive call is constant, O(1). 

How big is the subtree that is heapified?

The largest possible subtree (when the last row
is half full) is 2/3 the size of n so
the recursive call will take T(2n/3) time so the
recurrence is 

T(n) <= T(2n/3) + O(1) 

Using the master theorem, f(n) = 1, a = 1, b = 2/3 
so we use case 2 since 

so heapify is O(lgn)

Building -Heap

  • To build a heap out of an unsorted array we will repeatably call Heapify


    
    //pseudo-code
    Build-Heap(int A[])
     { A.heapsize = A.length();
      for (i = A.length() / 2 downto 1)
        heapify(A, i)
      
     }
    
    

 

Running Time of Heapify

  • The for loop is run n/2 times.
  • And we know that Heapify has running time O(lgn).
  • So the running time of Build-Heap is O(nlgn) (note that the depth of the run on each Heapify is many times constant and hence can be bound more accurately by O(n))

Example of Build-Heap

HeapSort

Use Heap to sort an array

 


Heapsort(A)
{  A.heapsize = A.length();
  build_heap(A);
  for index = A.length() to 2 do
    swap(A[1], A[index]); 
    A.heapsize = A.heapsize - 1;
    heapify(A, 1);
}

 

Running Time:

Since heapify takes O(lgn) time and we only need to make n-1 calls the algorithm runs in O(nlgn) time

Applications of Heaps

  • Heap sort: One of the best sorting methods being in-place and with no quadratic worst case scenarios.
  • Selection algorithms: Finding the min, max or both of them, median or even any k-th element in sublinear time can be done dynamically with heaps.
  • Graph algorithms: By using heaps as internal traversal data structures, run time will be reduced by an order of polynomial. Examples of such problems are Kruskal's minimal spanning tree algorithm and Dijkstra's shortest path problem.

 

 

© Lynne Grewe