krahets/hello-algo · error · Error

堆为空

Error message

堆为空

What it means

Thrown by pop() on a max-heap (MaxHeap) when the heap is empty. pop() swaps the root with the last leaf, removes the last element, then sifts the new root down to restore the heap property; calling it on an empty heap has no element to return, so the guard prevents an invalid swap/undefined return.

Source

Thrown at codes/javascript/chapter_heap/my_heap.js:85

    /* 从节点 i 开始,从底至顶堆化 */
    #siftUp(i) {
        while (true) {
            // 获取节点 i 的父节点
            const p = this.#parent(i);
            // 当“越过根节点”或“节点无须修复”时,结束堆化
            if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;
            // 交换两节点
            this.#swap(i, p);
            // 循环向上堆化
            i = p;
        }
    }

    /* 元素出堆 */
    pop() {
        // 判空处理
        if (this.isEmpty()) throw new Error('堆为空');
        // 交换根节点与最右叶节点(交换首元素与尾元素)
        this.#swap(0, this.size() - 1);
        // 删除节点
        const val = this.#maxHeap.pop();
        // 从顶至底堆化
        this.#siftDown(0);
        // 返回堆顶元素
        return val;
    }

    /* 从节点 i 开始,从顶至底堆化 */
    #siftDown(i) {
        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: while (!heap.isEmpty()) { const x = heap.pop(); ... }.
  2. Check heap.size() > 0 before a single pop.
  3. Track enqueue/dequeue counts in the caller.
  4. If draining, break the loop on isEmpty() rather than catching the throw.

Example fix

// before
while (true) {
  const x = heap.pop(); // throws when drained
}
// after
while (!heap.isEmpty()) {
  const x = heap.pop();
}
Defensive patterns

Strategy: validation

Validate before calling

function safePop(heap) {
  if (!heap.isEmpty()) return heap.pop();
  throw new Error('heap empty');
}

Type guard

function heapHasElements(heap) {
  return heap.size() > 0;
}

Try / catch

try {
  const x = heap.pop();
} catch (e) {
  if (e instanceof Error && e.message === '堆为空') { /* drain complete */ } else throw e;
}

Prevention

When it happens

Trigger: Calling pop() more times than elements were pushed; popping a freshly constructed heap; popping after the last element was already removed; popping in a loop without an emptiness guard.

Common situations: Drain loops (while(true) heap.pop()); priority-queue consumers pulling more tasks than were enqueued; using the heap as a sorting sink without checking size.

Related errors


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