krahets/hello-algo · error · RangeError

Heap is empty.

Error message

Heap is empty.

What it means

A RangeError 'Heap is empty.' thrown by pop() in MaxHeap (my_heap.ts:84). pop() swaps the root with the last leaf, removes the tail, then sifts the new root down; on an empty heap there is nothing to swap or return, so the guard refuses the operation. peek() is NOT guarded, so it would return undefined on empty — pop is the only method that throws here.

Source

Thrown at zh-hant/codes/typescript/chapter_heap/my_heap.ts:84

    /* 從節點 i 開始,從底至頂堆積化 */
    private siftUp(i: number): void {
        while (true) {
            // 獲取節點 i 的父節點
            const p = this.parent(i);
            // 當“越過根節點”或“節點無須修復”時,結束堆積化
            if (p < 0 || this.maxHeap[i] <= this.maxHeap[p]) break;
            // 交換兩節點
            this.swap(i, p);
            // 迴圈向上堆積化
            i = p;
        }
    }

    /* 元素出堆積 */
    public pop(): number {
        // 判空處理
        if (this.isEmpty()) throw new RangeError('Heap is empty.');
        // 交換根節點與最右葉節點(交換首元素與尾元素)
        this.swap(0, this.size() - 1);
        // 刪除節點
        const val = this.maxHeap.pop();
        // 從頂至底堆積化
        this.siftDown(0);
        // 返回堆積頂元素
        return val;
    }

    /* 從節點 i 開始,從頂至底堆積化 */
    private siftDown(i: number): void {
        while (true) {
            // 判斷節點 i, l, r 中值最大的節點,記為 ma
            const l = this.left(i),
                r = this.right(i);
            let ma = i;
            if (l < this.size() && this.maxHeap[l] > this.maxHeap[ma]) ma = l;

View on GitHub (pinned to 69932aed18)

Solutions

  1. Guard every pop with `if (!heap.isEmpty()) heap.pop()` or loop with `while (!heap.isEmpty())`.
  2. Call isEmpty() (or size() === 0) before pop rather than relying on peek().
  3. Track the count you pushed and pop at most that many times.
  4. If a sentinel/undefined result is acceptable, wrap pop in a helper that returns undefined on empty.

Example fix

// before: off-by-one pops the empty heap and throws
while (heap.size() >= 0) {
    heap.pop();
}

// after: stop when empty
while (!heap.isEmpty()) {
    const top = heap.pop();
}
Defensive patterns

Strategy: validation

Validate before calling

// Never pop an empty heap
function safePop(heap: MaxHeap): number | undefined {
    return heap.isEmpty() ? undefined : heap.pop();
}
// usage:
while (!heap.isEmpty()) {
    const top = heap.pop();
}

Type guard

// Heap exposes isEmpty(); treat it as the emptiness guard
const hasElements = (heap: MaxHeap): boolean => !heap.isEmpty();

Try / catch

try {
    const top = heap.pop();
} catch (e) {
    if (e instanceof RangeError && /Heap is empty/.test(e.message)) {
        // nothing to pop; handle empty state
    } else throw e;
}

Prevention

When it happens

Trigger: Calling maxHeap.pop() when maxHeap.size() === 0 (i.e., maxHeap.isEmpty() is true). This happens when draining a heap in a loop and popping one more time than the number of elements, or calling pop on a freshly constructed `new MaxHeap()` with no initial array.

Common situations: Off-by-one in a while-pop loop (using `while (true)` or `<= size` instead of `while (!heap.isEmpty())`); popping after a previous pop already emptied the heap; treating peek()'s undefined as 'still has data' and then popping; draining a heap built from an empty or undefined input array.

Related errors


AI-assisted analysis of krahets/hello-algo@69932aed18 (2026-08-13). Data as JSON: /api/errors/d9ec2d1318bd70d9. Report an issue: GitHub.