- A Heap is a special Tree-based data structure in which the tree is an almost complete binary tree. Generally, Heaps can be of two types, min or max, and are sorted with a min or max value at the root.
- Binary Heaps can be stored as a single array. For zero indexed array with index
n:- Children are at
2n + 1and2n + 2 - Parent is at
floor((n - 1) / 2)
- Children are at
- The heap is one maximally efficient implementation of an abstract data type called a priority queue
- O (1) removal
- O (logN) search
- Memory overhead for storing methods
All Binary heaps:
- are complete and have a root. Complete is defined as
All levels are completely filled except possibly the last level, and the last level has all keys as left as possible
- For a Min Heap, each node is smaller than its children, and the root is minimum
- For a Max Heap, each node is larger than its children and the root is maximum
- Min Heap
- Max Heap
- Fibonacci Heap - excellent amortized operations by using multiple heaps
-
insert- O(logN) time- Insert in bottom level, lowest and leftmost position
- Swap with parent node until tree is correct, a.k.a Sift/Bubble Up
-
extract_min,extract_max- O(logN) time- Extract root
- Swap last element into root position
- Swap with children until tree is correct, a.k.a Sift/Bubble Down
- Return extracted root
replace,decrease,delete- these all involve modifying the value of a node, then resorting the tree as necessary
Javascript implementation
class MaxHeap {
constructor() {
this.values = [];
}
getChildIndex(idx) {
const timesTwo = idx * 2;
return [timesTwo + 1, timesTwo + 2];
}
getParentIndex(idx) {
return Math.floor((idx - 1) / 2);
}
insert(val) {
this.values.push(val);
this.bubbleUp();
return this.values;
}
bubbleUp() {
let index = this.values.length - 1;
const element = this.values[index];
while (index > 0) {
let parentIdx = this.getParentIndex(index);
let parent = this.values[parentIdx];
if (element <= parent) break;
this.values[parentIdx] = element;
this.values[index] = parent;
index = parentIdx;
}
}
extractMax() {
const max = this.values[0];
const end = this.values.pop();
if (this.values.length > 0) {
this.values[0] = end;
this.sinkDown();
}
return max;
}
sinkDown() {
let idx = 0;
const length = this.values.length;
const element = this.values[0];
while (true) {
let [leftIdx, rightIdx] = this.getChildIndex(idx);
let leftChild;
let rightChild;
let swapIdx;
if (leftIdx < length) {
leftChild = this.values[leftIdx];
if (leftChild > element) swapIdx = leftIdx;
}
if (rightIdx < length) {
rightChild = this.values[rightIdx];
if ((!swapIdx && rightChild > element) || (swapIdx && rightChild > leftChild)) {
swapIdx = rightIdx;
}
}
if (swapIdx == undefined) break;
this.values[idx] = this.values[swapIdx];
this.values[swapIdx] = element;
idx = swapIdx;
}
}
}