栈与队列经典面试题:用两个栈实现队列、用两个队列实现栈

用两个栈实现队列、用两个队列实现栈

题1:用两个栈实现队列

算法分析

栈的特点是先进后出,而队列的特点是先进先出。那么如何用栈来实现队列呢?

先看第一个栈:

1 2 3 4

根据先进后出原则,逐个出栈然后存储到下一个栈:

4 3 2 1

此时,再进行出栈,输出的将是:

4 3 2 1

这和最原始的栈内存"1 2 3 4"的队列化输出结果:"4 3 2 1"一致了!也就是,先进来的4元素,也先出去了!

算法设计

设计两个栈,第一个栈作为数据栈用于存储数据,第二个栈用于反转顺序!

对于由两个栈实现的队列,如果要返回队首的时候,就将第一个数据栈把数据都扔给第二个反转栈用于反转,随后就可以让先进来的栈尾元素到达栈首,此时返回栈首其实就是返回队首!

需要注意的是:

  1. 每次出队列前,都需要清空第一个数据栈,放到反转栈,这是为了保持次序
  2. 出队列结束后,为了下一个元素入进入队列顺序不乱,还需要让反转栈的元素重新倒回数据栈

题目描述和AC代码

cpp 复制代码
class MyQueue {
private:
    stack<int> inStk;
    stack<int> outStk;

    void turnToStack(stack<int>& inStk, stack<int>& outStk) {
        while (!outStk.empty()) {
            inStk.push(outStk.top());
            outStk.pop();
        }
    }
public:
    /** Initialize your data structure here. */
    MyQueue() {

    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        inStk.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        turnToStack(outStk, inStk);
        int ret = outStk.top();
        outStk.pop();
        turnToStack(inStk, outStk);
        return ret;
    }
    
    /** Get the front element. */
    int peek() {
        turnToStack(outStk, inStk);
        int ret = outStk.top();
        turnToStack(inStk, outStk);
        return ret;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return inStk.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

题2:用两个队列实现栈

为了能让队列实现栈,能否借助栈实现队列的思路进行反转呢?答案是否定的!

因为队列压根起不到反转的效果,于是这里需要重新设计算法!

算法分析

对于一个栈:

1 2 3 4

首先输出的应该是 1 ,因为 1 是最后一个进来的,要先出去!

那么,先用一个数据队列存储栈元素,队列的元素序列是

1 2 3 4

但是此时的队首是 4 而不是 1 怎么办呢?

再设计一个转存队列,用于存储队尾前的全部元素,例如:

2 3 4

这时候,数据队列里就只有 1 这一个元素了,此时的队首就是栈首!然后处理完后,再将转存队列的内容返回到数据队列中,因为队列不会改变次序,所以数据队列会成为:

2 3 4

这就是删除栈首的结果!

算法设计

设计两个队列,一个数据队列,一个缓存队列。

第一个数据队列存储栈数据,当需要弹栈的时候,将数据队列除了最后一个元素以外的数据都放到缓存队列!然后数据队列就只有一个元素了,就是最后进入的那个元素,就直接弹出即可,此时就实现了 "后进先出"

需要注意的是:

  1. 缓存只能缓存前 n - 1 个元素,不能把要弹栈的元素都缓存了
  2. 弹栈完成后,要将缓存的内容倒回数据队列,否则下一个数据入栈的时候,顺序会乱

题目描述及AC代码

cpp 复制代码
class MyStack {
private:
    queue<int> inQue;
    queue<int> outQue;
public:
    /** Initialize your data structure here. */
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        inQue.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        while (1 != inQue.size()) {
            outQue.push(inQue.front());
            inQue.pop();
        }
        int ret = inQue.front();
        inQue.pop();
        while (!outQue.empty()) {
            inQue.push(outQue.front());
            outQue.pop();
        }
        return ret;
    }
    
    /** Get the top element. */
    int top() {
        while (1 != inQue.size()) {
            outQue.push(inQue.front());
            inQue.pop();
        }
        int ret = inQue.front();
        outQue.push(inQue.front());
        inQue.pop();
        while (!outQue.empty()) {
            inQue.push(outQue.front());
            outQue.pop();
        }
        return ret;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return inQue.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */