Priority queues
A priority queue is an abstract data structure which supports two main operations:
- Adding an element to the queue
- Popping the element with the highest priority
Applications
- Heap sort.
- A* algorithm.
- Huffman encoding.
- Prim's MST algorithm.
- Discrete event-driven simulation.
- Network bandwidth management.
- Dijkstra's shortest-paths algorithm
- Optimization to many dynamic programming algorithms
* we will discuss some of these in the future lectures
Binary heap
The binary heap is an effective implementation of the priority queue structure.
It represents a perfectly balanced binary tree (except for the last level) with the following property:
For each child, the key in child <= key in parent. (max heap)
or
For each child, the key in child >= key in parent. (min heap)
min-heap
Operations
The (max)heap supports the following operations:
- Insert an element - O(log n)
- Retrieve the max element - O(1)
- Remove the max element - O (log n)
- Heapify - given a list, construct a heap from it - O(n)
Representation
The heap can be represented as a standard binary tree - nodes with pointers
or implicitly - as an array or list
Representation
The standard representation uses nodes with pointers to both children
class Node {
Key value;
Node leftChild;
Node rightChild;
}
The implicit representation uses the following index rules which ensure that the list will be filled consecutively
Root is at index 1;
Node with index i has children:
Left: 2*i
Right: 2*i+1
Node with index i has parent:
Parent: floor(i/2)
*Note: to implement insert and remove we need a pointer to the next node(from the previous slide) which we can get with O(1) in the implicit representation
Insert
Steps:
Put the new element to the next position
Assign current = inserted element
WHILE current != root AND current > parent(current)
swap( current, parent(current))
current = parent(current)
Update the next position
Remove
Steps:
Put the last value over the root value
Assign current = root
WHILE (has_left_child(current) AND current < left(current)) OR (has_right_child(current) AND current < right(current))
swap( current, larger_child(current))
current = larger_child(current)
Update the next position
Heapify
Task: Given N elements, construct a binary heap containing them.
Observation: we can insert each element consecutively and achieve O(n log n)
Bottom-up method: a faster approach - O(n). Goes from the bottom to the top of the tree and applies the same method as in remove (sink down - see previous slide)
Steps:
For i = n to 1
Assign current = nodes[i]
WHILE (has_left_child(current) AND current < left(current)) OR (has_right_child(current) AND current < right(current))
swap( current, larger_child(current))
current = larger_child(current)
Heapify
Task: Given N elements, construct a binary heap containing them.
Observation: we can insert each element consecutively and achieve O(n log n)
Bottom-up method: a faster approach - O(n). Goes from the bottom to the top of the tree and applies the same method as in remove (sink down - see previous slide)
Steps:
For i = n to 1
Assign current = nodes[i]
WHILE (has_left_child(current) AND current < left(current)) OR (has_right_child(current) AND current < right(current))
swap( current, larger_child(current))
current = larger_child(current)
The bottom-up method is faster because it makes use of the fact that most of the nodes in a binary tree are near the bottom and there are fewer levels to go down for these nodes
Heap
By Ivan Todorov
Heap
- 993