Priority Queue and Heap
- A Priority queue stores a collection of items. Each item is
    a pair of <key, element>. Usually but not always, the smaller
    the key the higher the priority.
- Priority queue operations:
  
  - insert
  
- removeMin
  
- minKey
  
- minElement
  
- other assistant operations: size, isEmpty, isFull, etc
  
 
- Typical Applications: to-do list
- Total order relation
  
  - keys in a priority queue can be arbitrary objects on which
      an order is defined
  
- two distinct items in a priority queue can have the same key
  
- mathematical concept of total order relation <=:
    
    - Reflexive property: x <= x
    
- Antisymmetric property: x <= y and y <= x implies x == y
    
- Transitive property: x <= y and y <= z implies x <= z
    
 
 
- Implementation of priority queue
  
  - unsorted list -- insert O(1), removeMin O(N) 
  
- sorted array -- insert O(N), removeMin O(1)
  
- heap -- insert O(logN), removeMin O(logN)
  
 
- ADT Heap: A heap is a binary tree storing <key, element> pairs
    in its nodes and satisfying the following properties:
  
  - Heap Order: for every node v other than the root, v's parent's priority
      is higher than or the same as v's priority.
  
- Complete Binary Tree.    
  
 
- Heap observation:
  
  - The height of a heap storing N <key, element> pairs is O(logN).
  
- The element with the highest priority is always stored in the root node. 
  
 
- Using heap to implement the priority queue
  
  - insert -- insert to the next spot after the last node,
                using upheap (starting from the new node, possible
                swap with parent) to restore the Heap Order
  
- removeMin -- swap root and last element, remove the last element,
                   using downheap (starting from root, possible swap with
                   one of the child nodes) to restore the Heap Order
  
 
- Implementation of heap -- using array
  
  - root node is at array[0]
  
- Given array[i], its parent node is at array[(i-1)/2] if i > 0;
      its left child node is at array[i*2+1] and its right child node
      is at array[i*2+2].
  
- The last element in a heap with N elements is at array[N-1].
  
- To insert a new element, insert to array[N] first, update N,
      then perform upheap to restore the Heap Order.
  
- To removeMin, swap array[0] and array[N-1] first, update N,
      then perform downheap to restore the Heap Order.
  
- Performance: insert -- O(logN), removeMin -- O(logN), minKey -- O(1),
      minElement -- O(1)
  
 
- Heap Sort
  
  - Using an array based heap
  
- Put N elements one by one into the heap using method insert
  
- Taking elements out one by one using method removeMin
  
- Performance -- O(NlogN)
  
- Space usage -- in place