用两个栈模拟队列:LIFO 到 FIFO 的转换实现与复杂度分析
如何用栈(LIFO,后进先出)来模拟队列(FIFO,先进先出)?这是深入理解数据结构本质、锻炼算法设计思维的绝佳案例。双栈模型巧妙地解决了顺序反转的问题,本文将详细拆解其原理、C 语言实现细节以及性能分析。
一、设计哲学与架构
1.1 核心思想:LIFO 到 FIFO 的转换
传统的队列操作要求元素从一端进入,从另一端离开。栈只能从同一端进出。要用栈模拟队列,关键在于将栈中倒置的元素顺序转化为正序。
双栈模型将队列职责拆分给两个独立的栈:
- 输入栈(s1):专门负责入队操作。所有新元素无条件推入这里,像一个高效的'原料仓库'。
- 输出栈(s2):专门负责出队或查看队头。它维护了队列的正确顺序,仅在需要提供队头元素时才被使用,像个面向客户的'售货柜台'。
1.2 数据流向与职责分离
我们可以把这个模型想象成一个餐厅系统:
- 输入栈 (s1) 是厨房:顾客订单依次堆叠在厨房工作台上。最晚下的订单在最上面。
- 输出栈 (s2) 是出菜口:当需要上菜时,从出菜口取。
- 转移操作是配菜:当出菜口空了,厨房会将所有订单一次性倒扣到出菜口的托盘上。由于栈的反转特性,原本厨房工作台最底下的(最早的订单)现在变成了出菜口托盘的最上面,等待被取出。
这种职责分离确保了 s1 永远只做入队,保持 O(1) 效率;而 s2 只在必要时才进行昂贵的转移操作。
1.3 操作序列模拟
模拟一个操作序列:push(1), push(2), peek(), pop(), push(3), pop()。
| 操作 | stackIn 状态 (栈底 → 栈顶) | stackOut 状态 (栈底 → 栈顶) | transfer() 动作 | 结果 |
|---|---|---|---|---|
| push(1) | [1] | [] | 否 | - |
| push(2) | [1, 2] | [] | 否 | - |
| peek() | [1, 2] | [] | 是:[1, 2] → [2, 1] | stackOut 变为 [1, 2] (栈顶为 1)。返回 1 |
| pop() | [] | [2, 1] | 否 | 移除并返回 1 |
| push(3) | [3] | [2] | 否 | - |


