不用collections.deque而手写双栈模拟仅适用于面试考察栈能力或环境受限必须用栈的场景;真实项目应直接使用deque。核心是left_stack管左侧操作、right_stack管右侧操作,倒栈仅在目标栈空且需取数时触发,均摊o(1),但最坏o(n);需严格判空防indexerror,禁用for循环倒栈,len和bool基于两栈长度和,不支持高效随机访问。

为什么不用 collections.deque 而要手写双栈模拟?
因为 collections.deque 本身已是 O(1) 均摊双向队列,手写双栈的唯一合理场景是:面试考察栈抽象能力、或受限于环境(如只能用栈类)必须模拟。真实项目中直接用 deque,否则就是给自己加维护成本。
核心思路:一个栈存前半,一个栈存后半
把双向队列逻辑拆成两段:left_stack 管理「左侧插入/弹出」,right_stack 管理「右侧插入/弹出」。关键不是“左右对称”,而是让任意一端操作时,另一端数据处于可快速访问状态。
-
append()(右入)→ 直接压入right_stack -
appendleft()(左入)→ 直接压入left_stack -
pop()(右出)→ 若right_stack非空,直接pop();否则把left_stack全部倒进right_stack再pop() -
popleft()(左出)→ 若left_stack非空,直接pop();否则把right_stack全部倒进left_stack再pop()
倒栈操作只在目标栈为空且需取数时触发,均摊时间复杂度仍是 O(1)。
容易踩的坑:倒栈时机和边界判断
常见错误是提前倒栈,或忽略空栈检查,导致 IndexError: pop from empty list。
- 倒栈前必须确认目标栈为空,且源栈非空——否则白做一次 O(n) 操作
-
pop()和popleft()都要先判空再决定是否倒栈,不能只依赖倒栈后的长度 - 倒栈过程用
while stack: target.append(stack.pop()),别用for循环配range(len(stack)),后者会因动态修改长度出错 - 两个栈都为空时,所有操作都该抛
IndexError,而不是静默返回None
性能与兼容性注意点
双栈模拟在最坏情况下(连续交替调用 pop() 和 popleft())会频繁倒栈,单次操作退化为 O(n),但均摊仍是 O(1)。Python 列表作为栈足够快,无需改用 queue.LifoQueue —— 后者带线程安全开销,纯属画蛇添足。
如果需要支持 __len__() 或 __bool__(),直接返回 len(left_stack) + len(right_stack),别实时倒栈统计。
真正难处理的是随机索引访问(__getitem__(i)),双栈结构天然不支持 O(1) 下标访问;若业务真需要,说明不该用栈模拟,该换真实双向链表或 deque。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











