{"record":{"id":"0652b4a80caba052","repo":"krahets/hello-algo","slug":"error-0652b4","errorCode":null,"errorMessage":"双向队列为空","messagePattern":"双向队列为空","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"codes/python/chapter_stack_and_queue/array_deque.py","lineNumber":76,"sourceCode":"\n    def pop_first(self) -> int:\n        \"\"\"队首出队\"\"\"\n        num = self.peek_first()\n        # 队首指针向后移动一位\n        self._front = self.index(self._front + 1)\n        self._size -= 1\n        return num\n\n    def pop_last(self) -> int:\n        \"\"\"队尾出队\"\"\"\n        num = self.peek_last()\n        self._size -= 1\n        return num\n\n    def peek_first(self) -> int:\n        \"\"\"访问队首元素\"\"\"\n        if self.is_empty():\n            raise IndexError(\"双向队列为空\")\n        return self._nums[self._front]\n\n    def peek_last(self) -> int:\n        \"\"\"访问队尾元素\"\"\"\n        if self.is_empty():\n            raise IndexError(\"双向队列为空\")\n        # 计算尾元素索引\n        last = self.index(self._front + self._size - 1)\n        return self._nums[last]\n\n    def to_array(self) -> list[int]:\n        \"\"\"返回数组用于打印\"\"\"\n        # 仅转换有效长度范围内的列表元素\n        res = []\n        for i in range(self._size):\n            res.append(self._nums[self.index(self._front + i)])\n        return res\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/codes/python/chapter_stack_and_queue/array_deque.py#L58-L94","documentation":"IndexError '双向队列为空' (deque is empty) raised by ArrayDeque.peek_first. Reading the front slot of an empty circular deque would return stale memory, so the guard refuses the operation. pop_first also routes through peek_first and inherits the failure.","triggerScenarios":"Calling deque.peek_first() or deque.pop_first() when _size == 0.","commonSituations":"BFS or sliding-window code that pops without a length check; mixing peek_first and pop_first where the peek is assumed to always succeed; reusing a deque after draining it.","solutions":["Call is_empty() before peek_first or pop_first.","When popping, prefer: val = dq.peek_first() if not dq.is_empty() else default.","Reset or recreate the deque if its lifetime spans multiple drain phases."],"exampleFix":"// before\nhead = dq.peek_first()  # raises if drained\n// after\nhead = dq.peek_first() if not dq.is_empty() else None","handlingStrategy":"validation","validationCode":"def safe_peek_first(dq):\n    return dq.peek_first() if not dq.is_empty() else None","typeGuard":"def deque_non_empty(dq) -> bool:\n    return not dq.is_empty()","tryCatchPattern":"try:\n    head = dq.peek_first()\nexcept IndexError:\n    head = None","preventionTips":["Check is_empty() before peek_first or pop_first.","Return a sentinel instead of peeking unconditionally.","In BFS, check emptiness between operations, not once per iteration."],"tags":["deque","circular-array","index-error","empty-structure","peek"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}