krahets/hello-algo · error · IndexError

堆为空

Error message

堆为空

What it means

IndexError with message '堆为空' (heap is empty), raised by MaxHeap.pop. The implementation swaps the root with the last leaf, removes the leaf, then sifts down; calling pop on an empty heap would dereference an invalid root, so it is guarded with is_empty().

Source

Thrown at codes/python/chapter_heap/my_heap.py:77

    def sift_up(self, i: int):
        """从节点 i 开始,从底至顶堆化"""
        while True:
            # 获取节点 i 的父节点
            p = self.parent(i)
            # 当“越过根节点”或“节点无须修复”时,结束堆化
            if p < 0 or self.max_heap[i] <= self.max_heap[p]:
                break
            # 交换两节点
            self.swap(i, p)
            # 循环向上堆化
            i = p

    def pop(self) -> int:
        """元素出堆"""
        # 判空处理
        if self.is_empty():
            raise IndexError("堆为空")
        # 交换根节点与最右叶节点(交换首元素与尾元素)
        self.swap(0, self.size() - 1)
        # 删除节点
        val = self.max_heap.pop()
        # 从顶至底堆化
        self.sift_down(0)
        # 返回堆顶元素
        return val

    def sift_down(self, i: int):
        """从节点 i 开始,从顶至底堆化"""
        while True:
            # 判断节点 i, l, r 中值最大的节点,记为 ma
            l, r, ma = self.left(i), self.right(i), i
            if l < self.size() and self.max_heap[l] > self.max_heap[ma]:
                ma = l
            if r < self.size() and self.max_heap[r] > self.max_heap[ma]:
                ma = r

View on GitHub (pinned to 69932aed18)

Solutions

  1. Check heap.is_empty() before each pop.
  2. Drive the drain loop with while not heap.is_empty(): val = heap.pop().
  3. If you must pop a fixed count, clamp the count to heap.size().

Example fix

// before
while True:
    top = heap.pop()  # raises on last iteration
// after
while not heap.is_empty():
    top = heap.pop()
Defensive patterns

Strategy: validation

Validate before calling

def safe_pop(heap):
    if heap.is_empty():
        return None
    return heap.pop()

Type guard

def heap_has_items(heap) -> bool:
    return not heap.is_empty()

Try / catch

try:
    val = heap.pop()
except IndexError:
    val = None

Prevention

When it happens

Trigger: Calling heap.pop() when size() == 0 — e.g. draining the heap in a loop without an is_empty guard, or popping more elements than were pushed.

Common situations: A while True loop that pops until exhausted but forgets the termination check; off-by-one in a k-largest/k-smallest selection that pops one too many times; reusing a heap instance across runs without resetting size tracking.

Related errors


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