class MinPriorityQueue { heap: number[] = []; insert(val: number) { this.heap.push(val); this.bubbleUp(); } bubbleUp() { let idx = this.heap.length - 1; const element = this.heap[idx]; while (idx > 0) { let parentIdx = Math.floor((idx - 1) / 2); let parent = this.heap[parentIdx]; if (element >= parent) break; this.heap[parentIdx] = element; this.heap[idx] = parent; idx = parentIdx; } } } const pq = new MinPriorityQueue(); pq.insert(5); pq.insert(3); pq.insert(8); pq.insert(1); console.log(pq.heap);
After inserting 5, heap is [5]. Insert 3, bubbleUp swaps 3 and 5 → [3,5]. Insert 8, no swap → [3,5,8]. Insert 1, bubbleUp swaps 1 with 3, then with root → [1,3,8,5].
class MinPriorityQueue { heap: number[] = [1, 3, 8, 5]; extractMin() { const min = this.heap[0]; const end = this.heap.pop(); if (this.heap.length > 0 && end !== undefined) { this.heap[0] = end; this.sinkDown(); } return min; } sinkDown() { let idx = 0; const length = this.heap.length; const element = this.heap[0]; while (true) { let leftChildIdx = 2 * idx + 1; let rightChildIdx = 2 * idx + 2; let leftChild, rightChild; let swap = null; if (leftChildIdx < length) { leftChild = this.heap[leftChildIdx]; if (leftChild < element) swap = leftChildIdx; } if (rightChildIdx < length) { rightChild = this.heap[rightChildIdx]; if ((swap === null && rightChild < element) || (swap !== null && rightChild < leftChild!)) swap = rightChildIdx; } if (swap === null) break; this.heap[idx] = this.heap[swap]; this.heap[swap] = element; idx = swap; } } } const pq = new MinPriorityQueue(); pq.extractMin(); console.log(pq.heap);
Remove 1, replace root with 5 → [5,3,8]. Sink down swaps 5 with 3 → [3,5,8].
Priority queues efficiently insert elements and extract the highest priority element (min or max) but do not keep all elements fully sorted internally.
sinkDown() {
let idx = 0;
const length = this.heap.length;
const element = this.heap[0];
while (true) {
let leftChildIdx = 2 * idx + 1;
let rightChildIdx = 2 * idx + 2;
let leftChild, rightChild;
let swap = null;
if (leftChildIdx < length) {
leftChild = this.heap[leftChildIdx];
if (leftChild < element) swap = leftChildIdx;
}
if (rightChildIdx < length) {
rightChild = this.heap[rightChildIdx];
if ((swap === null && rightChild < element) || (swap !== null && rightChild < leftChild!)) swap = rightChildIdx;
}
if (swap === null) break;
this.heap[idx] = this.heap[swap];
this.heap[swap] = element;
idx = swap;
}
}If leftChildIdx is out of range, leftChild is undefined. Comparing rightChild < leftChild causes TypeError.
class MaxPriorityQueue { heap: number[] = []; insert(val: number) { this.heap.push(val); this.bubbleUp(); } bubbleUp() { let idx = this.heap.length - 1; const element = this.heap[idx]; while (idx > 0) { let parentIdx = Math.floor((idx - 1) / 2); let parent = this.heap[parentIdx]; if (element <= parent) break; this.heap[parentIdx] = element; this.heap[idx] = parent; idx = parentIdx; } } extractMax() { const max = this.heap[0]; const end = this.heap.pop(); if (this.heap.length > 0 && end !== undefined) { this.heap[0] = end; this.sinkDown(); } return max; } sinkDown() { let idx = 0; const length = this.heap.length; const element = this.heap[0]; while (true) { let leftChildIdx = 2 * idx + 1; let rightChildIdx = 2 * idx + 2; let leftChild, rightChild; let swap = null; if (leftChildIdx < length) { leftChild = this.heap[leftChildIdx]; if (leftChild > element) swap = leftChildIdx; } if (rightChildIdx < length) { rightChild = this.heap[rightChildIdx]; if ((swap === null && rightChild > element) || (swap !== null && rightChild > leftChild!)) swap = rightChildIdx; } if (swap === null) break; this.heap[idx] = this.heap[swap]; this.heap[swap] = element; idx = swap; } } } const pq = new MaxPriorityQueue(); pq.insert(10); pq.insert(20); pq.extractMax(); pq.insert(15); pq.extractMax(); pq.insert(5); console.log(pq.heap.length);
Insert 10 (1 element), insert 20 (2 elements), extractMax removes 20 (1 element), insert 15 (2 elements), extractMax removes 15 (1 element), insert 5 (2 elements). Final count is 2.
