Oct 24, 2022
Operation | Lazy | Proactive |
---|---|---|
enqueue | $O(1)$ | $O(n)$ |
dequeue | $O(n)$ | $O(1)$ |
head | $O(n)$ | $O(1)$ |
Can we do better?
Idea: Keep the priority queue "kinda" sorted.
Larger items tend to be closer to the front of the list. The closer we are to the front of the list, the more sorted it gets.
Challenge: How do we keep track of which elements are still sorted?
Idea: Organize the priority queue as a tree
Directed: A directed edge means "≥"
Organize the priority queue as a tree
Directed: A directed edge means "≥"
Binary: Max out-degree of 2 (Easy to reason about)
Complete: Every "level" except the last is full
All nodes in the last level are all-the-way left
Ordering by "≥" gets us a "Max-Heap"
What is the depth of a binary heap containing $n$ items?
What is the depth of a binary heap containing $n$ items?
$$n = O\left(\sum_{i = 1}^{\ell_{max}} 2^i\right) = O\left(2^{\ell_{max}}\right)$$
$$\ell_{max} = O\left(\log(n)\right)$$
Idea: Insert element at next available spot, then fix.
def fixUp[A: Ordering](current: Vertex[A]): Unit =
{
if(current.parent.isDefined){
val parent = current.parent.get
if( Ordering[A].lt( parent.value, current.value ) ){
swap(current.value, parent.value)
fixUp(parent)
}
}
}
What's the complexity?
(How many swaps are required?)
Idea: Replace root with last element, then fix.
def fixDown[A: Ordering](current: Vertex[A]): Unit =
{
if(current.leftChild.isDefined){
val left = current.leftChild.get
if( Ordering[A].lt( current.value, left.value ) ){
if(current.rightChild.isDefined){
val right = current.rightChild.get
if( Ordering[A].lt( right.value, left.value ) ){
swap(current.value, left.value); fixDown(left)
} else {
swap(current.value, right.value); fixDown(right)
}
} else {
swap(current.value, left.value); fixDown(left)
}
} else if(current.rightChild.isDefined) {
val right = current.rightChild.get
if( Ordering[A].lt( current.value, right.value ) ){
swap(current.value, right.value); fixDown(right)
}
}
}
}
What's the complexity?
Operation | Lazy | Proactive | Heap |
---|---|---|---|
enqueue | $O(1)$ | $O(n)$ | $O(\log(n))$ |
dequeue | $O(n)$ | $O(1)$ | $O(\log(n))$ |
head | $O(n)$ | $O(1)$ | $O(1)$ |
Idea: Use an ArrayBuffer to store the heap.