krahets/hello-algo · error · IndexError

双向队列为空

Error message

双向队列为空

What it means

IndexError '双向队列为空' (deque is empty) raised by LinkedListDeque.pop (the shared front/back removal routine). Removing from an empty doubly-linked list would dereference a None head/rear, so the guard blocks it. pop_first and pop_last both delegate here.

Source

Thrown at 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. Guard with is_empty() before pop_first or pop_last.
  2. In two-ended loops, check emptiness between every pop, not once per iteration.
  3. If a pop is optional, route through a helper that returns a default.

Example fix

// before
val = dq.pop_last()  # raises when drained
// after
val = dq.pop_last() if not dq.is_empty() else None
Defensive patterns

Strategy: validation

Validate before calling

def safe_pop(dq, front=True):
    return dq.pop(front) if not dq.is_empty() else None

Type guard

def deque_non_empty(dq) -> bool:
    return not dq.is_empty()

Try / catch

try:
    val = dq.pop_first()
except IndexError:
    val = None

Prevention

When it happens

Trigger: Calling deque.pop_first() or deque.pop_last() when the deque holds no nodes.

Common situations: Work-stealing or BFS front/back draining where one end is exhausted before the other; symmetric processing that assumes both ends stay non-empty; calling pop_last on a freshly constructed deque.

Related errors


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