krahets/hello-algo · error · IndexError

ヒープが空です

Error message

ヒープが空です

What it means

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.

Source

Thrown at ja/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
            # 2 つのノードを交換
            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 `if not heap.is_empty(): heap.pop()` before each pop.
  2. Loop with `while not heap.is_empty():` as the drain condition.
  3. Guard the constructor input: if the source list is empty, skip heap operations.
  4. Count pops against heap.size() to avoid over-draining.

Example fix

// before
while True:
    top = heap.pop()  # IndexError when drained

// after
while not heap.is_empty():
    top = heap.pop()
Defensive patterns

Strategy: validation

Validate before calling

if not heap.is_empty():
    val = heap.pop()

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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