【数据结构】双栈实现队列&队列实现栈思路和实现

引言

一、双栈实现队列

在这里插入图片描述
在这里插入图片描述

我的题解


/**
 * @Description: 使用两个栈 实现队列 —— 进和出
 * @param {*}
 * @return {*}
 * @notes: 关键:s1设置为队尾, s2设置为对头
 *              ① 出栈的时候如果为空,则 s1入s2; 再出队。
 *              ② 入栈则放到s1里面。
 *              ③ 如果 s1和s2同时为空——出栈的时候  则为空队列  返回-1。
 */
class CQueue {
public:
    CQueue() {
    }
    
    void appendTail(int value) {
        s1.push(value);
    }
    
    int deleteHead() {
        if(s2.empty()){
            while(!s1.empty()){
                int s = s1.top();
                s1.pop();
                s2.push(s);
            }
        }
        if(s2.empty() && s1.empty()){
            return -1;
        }

        // 有数值
        int tmp = s2.top();
        s2.pop();
        return tmp;
    }
private:
    stack<int> s1;
    stack<int> s2;
};

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

更多的功能


/**
 * @Description: 使用两个栈 实现队列 —— 进和出
 * @param {*}
 * @return {*}
 * @notes: 关键:s1设置为队尾, s2设置为对头
 *              ① 出栈的时候如果为空,则 s1入s2; 再出队。
 *              ② 入栈则放到s1里面。
 *              ③ 如果 s1和s2同时为空——出栈的时候  则为空队列  返回-1。
 */
class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {

    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        s1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if(s2.empty()){
            while(!s1.empty()){
                int s = s1.top();
                s1.pop();
                s2.push(s);
            }
        }
        if(s2.empty() && s1.empty()){
            return -1;
        }

        // 有数值
        int tmp = s2.top();
        s2.pop();
        return tmp;
    }

    
    /** Get the front element. */
    int peek() {
        if(s2.empty()){
            while(!s1.empty()){
                int s = s1.top();
                s1.pop();
                s2.push(s);
            }
        }
        if(s2.empty() && s1.empty()){
            return -1;
        }
        // 有数值
        int tmp = s2.top();
        return tmp;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if(s2.empty() && s1.empty()){
            return true;
        }
        return false;
    }
    
private:
    stack<int> s1;
    stack<int> s2;
};


至此,就用栈结构实现了一个队列,核心思想是利用两个栈互相配合。

值得一提的是,这几个操作的时间复杂度是多少呢?其他操作都是 O(1),有点意思的是peek操作,调用它时可能触发while循环,这样的话时间复杂度是 O(N),但是大部分情况下while循环不会被触发,时间复杂度是 O(1)。由于pop操作调用了peek,它的时间复杂度和peek相同。

像这种情况,可以说它们的最坏时间复杂度是 O(N),因为包含while循环,可能需要从s1往s2搬移元素。

但是它们的均摊时间复杂度是 O(1),这个要这么理解:对于一个元素,最多只可能被搬运一次,也就是说peek操作平均到每个元素的时间复杂度是 O(1)。

二、队列实现栈

使用相对暴力的方法——直接倒转前n-1 个放回去。
stackTop 来记录队头的元素。

在这里插入图片描述
在这里插入图片描述

我的题解

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        q.push(x);
        stackTop = x;
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        if(q.empty()){
            return -1;
        }
        int sz = q.size()-1;
        while(sz--){
            int tmp = q.front();
            q.pop();
            q.push(tmp);
        }
        int tmp = q.front();
        stackTop = q.back();  // 【注意这里!!】
        q.pop();
        return tmp;
    }
    
    /** Get the top element. */
    int top() {
        return stackTop;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return q.empty();
    }
private:
    int stackTop;
    queue<int> q;
};

三、总结

很明显,用队列实现栈的话,pop 操作时间复杂度是 O(N),其他操作都是 O(1)。

个人认为,用队列实现栈没啥亮点,但是 用双栈实现队列是值得学习的

出栈顺序本来就和入栈顺序相反,但是从栈s1搬运元素到s2之后,s2中元素出栈的顺序就变成了队列的先进先出顺序,这个特性有点类似「负负得正」,确实不容易想到。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值