【算法】【c++】两个栈实现一个队列

【算法】两个栈实现一个队列

1 基本概念

  1. 队列(Queue)
    队列是一种先进先出(FIFO, First-In-First-Out)的数据结构。入队的第一个元素一定是出队的第一个元素。

  2. 栈(Stack)
    栈是一种后进先出(LIFO, Last-In-First-Out)的数据结构。新加入的元素在栈顶,取出时也是从栈顶取。

2 用两个栈实现队列的思路

由于队列要求最先进入的元素最先被处理,而栈正好相反(最后进入的元素最先被处理),因此直接用一个栈无法模拟队列的行为。解决方法是使用两个栈,分别称为:

  • 输入栈(inStack):用于保存所有入队的元素。

  • 输出栈(outStack):用于执行出队操作和访问队首元素。

为什么需要两个栈?

当你把元素依次压入第一个栈(inStack)时,它们在栈中的顺序是逆序的。假设依次入队元素 1, 2, 3,在 inStack 中,出栈顺序为:3,2,1,这并不是队列的正确顺序(应为 1 先出)。
关键: 通过将 inStack 中的所有元素一次性弹出并压入第二个栈(outStack),顺序就会被反转:

  • 弹出顺序:3, 2, 1
  • 压入 outStack 后:弹出顺序:1,2,3
    此时,outStack 的栈顶正好是最早进入的元素,也就是队列的队首元素。

3 操作流程详细解释

1. 入队操作(push)

  • 操作: 直接将新元素压入 inStack。
  • 原因: 入队时只需要保存元素,暂时不考虑顺序问题,因为出队时会进行转换。
  • 时间复杂度: O(1)

假设执行 push(1)push(2)push(3) 后,inStack 状态(从栈底到栈顶):[1, 2, 3]

2. 出队操作(pop)

  • 情况1:当 outStack 非空
    • 直接从 outStack 弹出栈顶元素,这个元素就是队首。
  • 情况2:当 outStack 为空
    • 将 inStack 中所有元素依次弹出,然后压入 outStack(在这个过程中,顺序被完全反转)。
    • 弹出 outStack 的栈顶元素作为出队的结果。

详细步骤:

  1. 检查 outStack 是否为空:

    • 如果不为空,直接 pop() 即可。
    • 如果为空,进入下一步。
  2. 将 inStack 元素转移到 outStack:

    • 使用 while 循环:
      while (!inStack.empty()) {
          outStack.push(inStack.top());
          inStack.pop();
      }
      
    • 转移完成后,原本最先入队的元素现在位于 outStack 的栈顶。
  3. 从 outStack 弹出栈顶元素:

    • 这就是队列中最早入队的元素。

注意:

  • 转移操作只在 outStack 为空时进行,所以每个元素最多只会被移动一次,保证了均摊时间复杂度为 O(1)。

具体示例

假设进行如下操作:

  1. 入队:

    • push(1)
    • push(2)
    • push(3)
      此时:
    • inStack: [1, 2, 3] (1在底部,3在顶部)
    • outStack: 空
  2. 第一次出队(pop 或 peek):

    • outStack 为空,所以把 inStack 全部转移到 outStack。
      转移过程:
      • 弹出 3(inStack 变为 [1, 2]),压入 outStack → outStack: [3]
      • 弹出 2(inStack 变为 [1]),压入 outStack → outStack: [3, 2]
      • 弹出 1(inStack 变为 []),压入 outStack → outStack: [3, 2, 1]
    • 现在 outStack 的栈顶为 1,即队首元素。
    • 执行 pop 时,弹出 outStack 顶部的 1。
  3. 第二次出队:

    • 此时 outStack 非空(当前状态为 [3, 2],栈顶为 2),直接 pop 出 2。
  4. 后续操作:

    • 继续按上述规则进行,始终保持入队操作只对 inStack 进行,出队或 peek 操作如果 outStack 为空则转移,否则直接操作 outStack。

总结

  • 入队时:直接将新元素压入 inStack,保持 O(1) 时间。
  • 出队时:如果 outStack 为空,将 inStack 全部转移到 outStack,这个转移过程会将元素顺序反转,从而使得最早入队的元素出现在 outStack 栈顶;如果 outStack 非空,直接操作其栈顶。由于每个元素最多只转移一次,所以整体的均摊时间复杂度是 O(1)。

这种设计利用了两个栈之间的顺序反转特性,有效地模拟了队列的 FIFO 行为,同时在实际应用中表现出了高效性。

class Solution {
  public:
    void push(int node) {
        inStack.push(node);
    }

    int pop() {
        if (outStack.empty()) {
            while(!inStack.empty()) {
                int n = inStack.top();
                inStack.pop();
                outStack.push(n);
            }

        }
        int n = outStack.top();
        outStack.pop();
        return n;

    }

    //设置两个栈 一个用来push数据,一个用来pop数据
  private:
    stack<int> inStack;//push
    stack<int> outStack;//pop
};
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值