1. 程式人生 > 實用技巧 >棧與佇列

棧與佇列

佇列:先進先出

棧:先進後出

幾個基礎的問題:

  1. C++中stack 是容器麼?
  2. 我們使用的stack是屬於那個版本的STL?
  3. 我們使用的STL中stack是如何實現的?
  4. stack 提供迭代器來遍歷stack空間麼?

棧和佇列和C++STL裡面的兩個資料結構。

棧:先進後出

棧提供push、pop等介面,所有元素必須符合先進後出規則,所以棧不提供走訪功能,也不提供迭代器iterator,不像是set或者是map提供迭代器來遍歷所有元素。

「棧是以底層容器完成其所有的工作,對外提供統一的介面,底層容器是可插拔的(也就是說我們可以控制使用哪種容器來實現棧的功能)。」

所以STL中棧往往不被歸類為容器,而被歸類為container adapter(容器介面卡)

「我們常用的SGI STL,如果沒有指定底層實現的話,預設是以deque為預設情況下棧的低層結構。」

deque是一個雙向佇列,只要封住一段,只開通另一端就可以實現棧的邏輯了。

「SGI STL中 佇列底層實現預設情況下一樣使用deque實現的。」

我們也可以指定vector為棧的底層實現

佇列 先進先出的資料結構,同樣不允許有遍歷行為,不提供迭代器,SGI STL中佇列一樣是以deque為預設情況下的底部結構。

也可以指定list 為起底層實現

所以STL中佇列也不被歸類為容器,而被歸類為container adapter( 容器介面卡)。

可以用棧來實現佇列:兩個棧可以實現佇列!

class
MyQueue { public: stack<int> stIn; stack<int> stOut; /** Initialize your data structure here. */ MyQueue() { } /** Push element x to the back of queue. */ void push(int x) { stIn.push(x); } /** Removes the element from in front of queue and returns that element.
*/ int pop() { if(stOut.empty()) { while(!stIn.empty()) { stOut.push(stIn.top()); stIn.pop(); } } int result = stOut.top(); stOut.pop(); return result; } /** Get the front element. */ int peek() { int res = this->pop();//這裡彈出了res stOut.push(res); return res; } /** Returns whether the queue is empty. */ bool empty() { return (stOut.empty() && stIn.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(); */

可以用佇列還實現棧!

class MyStack {
public:
    queue<int>que1;
    queue<int>que2;//用來備份的
    /** Initialize your data structure here. */
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        que1.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        //現在元素都在que1裡,隊尾的元素是需要pop的元素,需要把其他的都暫存到que2裡
        int size = que1.size();
        size--;
        while(size--) {
            que2.push(que1.front());
            que1.pop();
        }
        int result = que1.front();
        que1.pop();
        que1 = que2;//恢復que1
        while(!que2.empty())
            que2.pop();
        return result;
    }
    
    /** Get the top element. */
    int top() {
        return que1.back();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return que1.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();
 */

一個經典應用就是“有效的括號”問題。

逆波蘭表示式問題是棧的經典應用,也是一道比較難的題目,題目一定要記住一個規則:遇到數字則入棧;遇到算符則取出兩個數字進行計算,並將結果壓入棧中。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(int i=0; i<tokens.size(); i++) {
            if(tokens[i]=="+" || tokens[i]=="-" || tokens[i]=="*" || tokens[i]=="/") {//這裡一定要注意是雙引號
                int num1 = st.top();
                st.pop();
                int num2 = st.top();
                st.pop();
                if(tokens[i]=="+")
                    st.push(num1+num2);
                else if(tokens[i]=="-")
                    st.push(num2-num1);//這裡一定要注意相減的順序
                else if(tokens[i]=="*")
                    st.push(num1*num2);
                else//除法
                    st.push(num2/num1);//這裡一定要注意相除的順序
            }
            else
                st.push(stoi(tokens[i]));
        }
        int result = st.top();
        st.pop();
        return result;
    }
};