{"record":{"id":"55a8daa704bdb531","repo":"krahets/hello-algo","slug":"error-55a8da","errorCode":null,"errorMessage":"堆为空","messagePattern":"堆为空","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"codes/python/chapter_heap/my_heap.py","lineNumber":77,"sourceCode":"\n    def sift_up(self, i: int):\n        \"\"\"从节点 i 开始，从底至顶堆化\"\"\"\n        while True:\n            # 获取节点 i 的父节点\n            p = self.parent(i)\n            # 当“越过根节点”或“节点无须修复”时，结束堆化\n            if p < 0 or self.max_heap[i] <= self.max_heap[p]:\n                break\n            # 交换两节点\n            self.swap(i, p)\n            # 循环向上堆化\n            i = p\n\n    def pop(self) -> int:\n        \"\"\"元素出堆\"\"\"\n        # 判空处理\n        if self.is_empty():\n            raise IndexError(\"堆为空\")\n        # 交换根节点与最右叶节点（交换首元素与尾元素）\n        self.swap(0, self.size() - 1)\n        # 删除节点\n        val = self.max_heap.pop()\n        # 从顶至底堆化\n        self.sift_down(0)\n        # 返回堆顶元素\n        return val\n\n    def sift_down(self, i: int):\n        \"\"\"从节点 i 开始，从顶至底堆化\"\"\"\n        while True:\n            # 判断节点 i, l, r 中值最大的节点，记为 ma\n            l, r, ma = self.left(i), self.right(i), i\n            if l < self.size() and self.max_heap[l] > self.max_heap[ma]:\n                ma = l\n            if r < self.size() and self.max_heap[r] > self.max_heap[ma]:\n                ma = r","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/codes/python/chapter_heap/my_heap.py#L59-L95","documentation":"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().","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check heap.is_empty() before each pop.","Drive the drain loop with while not heap.is_empty(): val = heap.pop().","If you must pop a fixed count, clamp the count to heap.size()."],"exampleFix":"// before\nwhile True:\n    top = heap.pop()  # raises on last iteration\n// after\nwhile not heap.is_empty():\n    top = heap.pop()","handlingStrategy":"validation","validationCode":"def safe_pop(heap):\n    if heap.is_empty():\n        return None\n    return heap.pop()","typeGuard":"def heap_has_items(heap) -> bool:\n    return not heap.is_empty()","tryCatchPattern":"try:\n    val = heap.pop()\nexcept IndexError:\n    val = None","preventionTips":["Always drive heap-drain loops with while not heap.is_empty().","Track an external count and clamp pop operations to it.","Reset or recreate the heap between independent runs."],"tags":["heap","index-error","empty-structure","validation","pop"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}