{"record":{"id":"fbe663e2d53c01d5","repo":"krahets/hello-algo","slug":"error-fbe663","errorCode":null,"errorMessage":"ヒープが空です","messagePattern":"ヒープが空です","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"ja/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            # 2 つのノードを交換\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/ja/codes/python/chapter_heap/my_heap.py#L59-L95","documentation":"This IndexError (Japanese: 'ヒープが空です' = 'heap is empty') is raised by MaxHeap.pop() (my_heap.py:77) when the heap contains no elements. pop() swaps the root with the last leaf, removes the last element, then sifts down — all of which would crash on an empty list, so the guard prevents that. MaxHeap is a teaching max-heap built on a plain Python list.","triggerScenarios":"Calling pop() on a MaxHeap constructed from an empty list `MaxHeap([])`. Calling pop() more times than elements were pushed. Calling pop() after draining the heap in a loop without an is_empty() check.","commonSituations":"Draining a heap in `while True: heap.pop()` without a termination guard. Building a heap from filtered/empty input data. Off-by-one in a loop that pops n+1 times from an n-element heap.","solutions":["Check `if not heap.is_empty(): heap.pop()` before each pop.","Loop with `while not heap.is_empty():` as the drain condition.","Guard the constructor input: if the source list is empty, skip heap operations.","Count pops against heap.size() to avoid over-draining."],"exampleFix":"// before\nwhile True:\n    top = heap.pop()  # IndexError when drained\n\n// after\nwhile not heap.is_empty():\n    top = heap.pop()","handlingStrategy":"validation","validationCode":"if not heap.is_empty():\n    val = heap.pop()","typeGuard":"def heap_has_top(heap: MaxHeap) -> bool:\n    return not heap.is_empty()","tryCatchPattern":"try:\n    val = heap.pop()\nexcept IndexError:\n    # heap was empty\n    val = None","preventionTips":["Drain with `while not heap.is_empty():` rather than a fixed iteration count.","Guard pop() with is_empty() every time.","Validate the constructor input list is non-empty before heap operations.","Count pops against heap.size() to prevent over-draining."],"tags":["heap","python","index-error","empty","priority-queue"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}