krahets/hello-algo · error · IndexError

雙向佇列為空

Error message

雙向佇列為空

What it means

Raised by the internal pop(is_front) method of a doubly-linked-list-based deque when the deque has zero nodes. This method is called by both pop_first() (is_front=True) and pop_last() (is_front=False), so both public methods inherit the guard. The check tests is_empty() before attempting to dereference _front or _rear pointers.

Source

Thrown at zh-hant/codes/python/chapter_stack_and_queue/linkedlist_deque.py:66

        else:
            # 將 node 新增至鏈結串列尾部
            self._rear.next = node
            node.prev = self._rear
            self._rear = node  # 更新尾節點
        self._size += 1  # 更新佇列長度

    def push_first(self, num: int):
        """佇列首入列"""
        self.push(num, True)

    def push_last(self, num: int):
        """佇列尾入列"""
        self.push(num, False)

    def pop(self, is_front: bool) -> int:
        """出列操作"""
        if self.is_empty():
            raise IndexError("雙向佇列為空")
        # 佇列首出列操作
        if is_front:
            val: int = self._front.val  # 暫存頭節點值
            # 刪除頭節點
            fnext: ListNode | None = self._front.next
            if fnext is not None:
                fnext.prev = None
                self._front.next = None
            self._front = fnext  # 更新頭節點
        # 佇列尾出列操作
        else:
            val: int = self._rear.val  # 暫存尾節點值
            # 刪除尾節點
            rprev: ListNode | None = self._rear.prev
            if rprev is not None:
                rprev.next = None
                self._rear.prev = None
            self._rear = rprev  # 更新尾節點

View on GitHub (pinned to 69932aed18)

Solutions

  1. Check deque.is_empty() before calling pop_first() or pop_last()
  2. Use size() as the loop bound in dual-ended draining
  3. Wrap in try/except IndexError for defensive deque operations

Example fix

# before
val = deque.pop_first()

# after
val = deque.pop_first() if not deque.is_empty() else None
Defensive patterns

Strategy: validation

Validate before calling

if not deque.is_empty():
    val = deque.pop_first()
else:
    val = None

Try / catch

try:
    val = deque.pop_last()
except IndexError:
    val = None

Prevention

When it happens

Trigger: Calling pop_first() or pop_last() on a freshly constructed LinkedListDeque; draining from both ends until empty and then popping once more; calling pop() after a failed push that silently returned.

Common situations: Two-ended draining algorithms (palindrome checks, window processing); BFS/DFS deques that exhaust all nodes; testing with empty initial sequences.

Related errors


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