棧和隊列

棧:

特點:先進先出
成員函數
stack()--構造
empty()--判空
size() --求個數
top() --返回棧頂元素
push --壓棧
pop() --出棧

應用

  • 最小棧創建:(可直接返回棧中最小值,即在該棧中查找最小值複雜度爲O(1))

因爲棧中最小值是隨push和pop操作變化的,進棧時min會更新,出棧min也可能會更新,所以每個元素進棧時當前棧中最小值應該被保存下來

//  法一:
class MinStack{public :
MinStack() {

}

public void push(int x) {
    int tmp = stack.top();
    if(stack.isEmpty()||tmp>x){
        stack.push(x);
        stack.push(x);
    }
        else{
       stack.push(x);
        stack.push(tmp);
    }
}

public void pop() {
    s.pop();
    s.pop();
}

public int top() {
    return s.get(s.size()-2);
}

public int getMin() {
    return s.top();
}
private:
 stack<int> s;
}
//法二:在最小棧中封裝兩個棧,一個存元素,一個存最小值。
//       push:   當存入當前元素的值是目前棧中最小值或等於最小值時,就存進去
//       pop:     當出來的值等於存最小值棧中的棧頂元素時,兩個一起pop出,否則只pop存元素的
class MinStack {
public:
    MinStack() 
    {  
    }
    void push(int x) {
        svalue.push(x);
        if(smin.empty()||x<=smin.top())
        {   
            smin.push(x);
        }

    }

    void pop() {

        if(!svalue.empty())
        {
            if(svalue.top()==smin.top())
            {
                smin.pop();
            }
            svalue.pop();
        } 
    }

    int top() {   
        return svalue.top();
    }

    int getMin() {
        return smin.top();
    }
    private:
    stack<int> svalue;
    stack<int> smin;
};
  • 判斷出棧順序正不正確
class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if(pushV.size()!=popV.size())
        {
            return false;
        }
        int index=0;
        int outdex=0;
        stack<int> s;
        while(outdex<popV.size())
        {
            while(s.empty()||s.top()!=popV[outdex])   //s.empty()  因爲棧爲空的時候s.top()非法空間不可引用
            {
                if(index>=pushV.size())
                {
                    return false;
                }
                s.push(pushV[index]);
                index++;
            }
            outdex++;
            s.pop();
        }
        return true;
    }
};
  • 逆波蘭表達式求值

    class Solution {
    public:
    int evalRPN(vector<string>& tokens) {
         stack<int> s;
        int index=0;
        int x,y;
        if(tokens.size()==1)
        {
            return atoi(tokens[0].c_str());
        }
        while(index<tokens.size())
        {
    
            while(tokens[index]!="+"&&tokens[index]!="-"&&tokens[index]!="*"&&tokens[index]!="/")
            {
                s.push(atoi(tokens[index++].c_str()));            
            }
            y = s.top();
            s.pop();
            x = s.top();
            s.pop();
            switch(tokens[index++].c_str()[0])
            {
                case '+':s.push(x+y);break;
                case '-':s.push(x-y);break;
                case '*':s.push(x*y);break;
                case '/':{
                    if(y!=0)
                    s.push(x/y);
                    else
                        s.push(0);
                    break;
                }
    
            }      
        }
        return s.top();
    }
    };

在樹的遍歷中,也會用到棧,一定要練題!

隊列

特點:先進後出
成員函數
queue()--構造
empty()--判空
size() --求個數
front()--返回隊頭元素
back() --返回隊尾元素
push --壓棧
pop() --出棧

在此介紹一種很重要的隊列叫做優先隊列

優先隊列

按照堆的順序存儲元素,默認是通過vector來存儲的
他所用的函數模板是:

template <class T,class Container=vector<T>,class Compare=less<T>)

說明:1.在默認的情況下,創建的是大堆順序存儲,用的是less方法的比較
創建對象時,可通過傳greater對象來創建一個小堆的順序

//例:
priority_queue<int>  q1;
priority_queue<int,vector<int>,less<int>>  q2;
//q1和q2創建出來都是以vector容器,大根堆順序 存儲

priority_queue<int,deque<int>,greater<int>> q3;
//q3創建出來是以deque容器,小根堆順序 存儲
//根據形參賦值規則,要從頭開始賦值,所以要串時參時,傳比較方法一定要帶上承載容器
    vector<int> v{ 2, 5, 3, 8, 9, 0, 1 };
    priority_queue<int> q3(v.begin(), v.end());  

2.如果在優先級隊列中放自定義數據類型,用戶需要在自定義類型中提供>或 < 的重載

//例:
class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}
    bool operator<(const Date& d)const
    {
        return (_year < d._year) ||
            (_year == d._year && _month < d._month) ||
            (_year == d._year && _month == d._month && _day < d._day);
    }
    bool operator>(const Date& d)const
    {
        return (_year > d._year) ||
            (_year == d._year && _month > d._month) ||
            (_year == d._year && _month == d._month && _day > d._day);
    }
    /*bool operator<(const Date* d)const
    {
        return (_year < d->_year) ||
            (_year == d->_year && _month < d->_month) ||
            (_year == d->_year && _month == d->_month && _day < d->_day);
    }
    bool operator>(const Date* d)const
    {
        return (_year > d->_year) ||
            (_year == d->_year && _month > d->_month) ||
            (_year == d->_year && _month == d->_month && _day > d->_day);
    }*/
    friend ostream& operator<<(ostream& _cout, const Date& d)
    {
        _cout << d._year << "-" << d._month << "-" << d._day;
        return _cout;
    }

private:
    int _year;
    int _month;
    int _day;
};
class  Less
{
public:
    bool operator()(const Date* pLeft, const Date* pRight){
        return *pLeft < *pRight;

    }
};

void Test(){
    Date d1(2019, 10, 21);
    Date d2(2019, 10, 20);
    Date d3(2019, 10, 22);

    priority_queue<Date> q1;
  q1.push(d1);
    q1.push(d2);
    q1.push(d3);

//對於指針,如果不提供比較方法,會用地址大小來使用堆排序
//如果想按照指針所指向空間裏存放的元素來比較,也要自己提供比較方式
//因而,要按照自己的需求排序時,都要自己提供比較方式才能達到目的
//如下文中的Less方法
    priority_queue<Date*, vector<Date*>, Less> q2;    
    q2.push(&d1);
    q2.push(&d2);
    q2.push(&d3);
}

提出一個重要概念:

容器適配器:

適配器是一種設計模式(設計模式是一套被反覆使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結),該中模式是將一個類的接口轉換成客戶希望的另外一個接口。
在類中具體實現方式:一個類在底層通過將其他容器進行封裝,通過提供不同的函數接口,以達到不同的功能。
stack、queue、priority_queue 都是容器適配器,因爲在STL中,每個容器都有自己的實現方式,而他們只是通過對其他容器進行封裝而成,因爲是容器適配器,而並不是容器

stack、queue、priority_queue底層的大概實現方式

namespace MyStack{
    template<class T,class Container=deque<T>>  //默認用棧承載
    class stack{
    public:
        stack(){

        }
        void push(const T &value){
            q.push_back(value);
        }
        void pop(){
            q.pop_back();
        }
        T& top(){
            return q.back();
        }
        const T& top() const
        {
            return q.back();
        }
        size_t size(){
            return q.size();
        }
        bool empty(){
            return q.empty();
        }
    private:
        Container  q;
    };
}

void Test2()
{
    MyStack::stack<int,list<int>> s1;
    s1.push(1);
    s1.push(2);
    s1.push(3);
    s1.pop();
    cout << s1.size() << endl;
    cout << s1.empty() << endl;
}
namespace MyQueue{
    template<class T, class Container = deque<T>>
    class queue{
    public:
        queue(){

        }
        void push(const T &value){
            q.push_back(value);
        }
        void pop(){
            q.pop_front();
        }

        T& front(){
            return q.front();
        }
        const T& front() const
        {
            return q.front();
        }
        T& back() 
        {
            return q.back();
        }
        const T& back() const
        {
            return q.back();
        }

        size_t size(){
            return q.size();
        }

        bool empty(){
            return q.empty();
        }
    private:
        Container  q;     、
        //用的是一個其他容器,在該類中提共其他方法在進行封裝就成了棧
    };
}

void Test3()
{
    MyQueue::queue<int,list<int>> q1;
    q1.push(1);
    q1.push(2);
    q1.push(3);
    q1.pop();

    cout << q1.size() << endl;
    cout << q1.empty() << endl;
}

爲什麼stack和queue使用的是deque而不是vector?
因爲對於deque來說,擴容是很容易的,只是將指針改變一下,而vercot又得重新將元素搬來搬去效率很低。此外,棧和隊列不會去遍歷(不提供迭代器),這個特性又把deque的弊端給忽略了。
不用list是因爲list的空間利用率不高

namespace MyPriorityqueue{
    template <class T,class Contain=vector<T>,class Compare=less<T>>
    class priority_queue{
    public:

        priority_queue()
            :_con()
        {

        }
        template <class Iterator>
        priority_queue(Iterator start, Iterator end)
            :_con(start, end)
        {

            for (int i =( _con.size()-2)/2; i >=0; i--)
            {
                AdjustDown(i);
            }
        }
        void size(){
            return _con.size();
        }
        bool empty(){
            return _con.empty();
        }
        void push(const T& value){
            _con.push_back(value);
            AdjustUP(_con.size() - 1);

        }
        void pop(){
            swap(_con.front(), _con.back());
            _con.pop_back();
            AdjustDown(0);

        }

    private:
        void AdjustDown(int parent){
            int child = parent * 2 + 1;
            while (child<_con.size())
            {
                if (child+1<_con.size()&&_comp(_con[child], _con[child + 1]))
                {
                    child += 1;
                }
                if (_comp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    parent = child;
                    child = parent * 2 + 1;
                }
                else
                    return;

            }
        }
        void AdjustUP(int child)
        {
            int parent = (child - 1) / 2;
            while (child>0){
                if (_comp(_con[parent],_con[child]))
                {
                    swap(_con[parent], _con[child]);
                    child = parent;
                    parent = (child - 1) / 2;           
                }
                else{
                    return;
                }
            }
        }
    private:
        Contain _con;
        Compare _comp;
    };

}

void Test4(){
    deque<int> dq{ 1, 2, 3 ,5,6,2};
    MyPriorityqueue::priority_queue<int,deque<int>,greater<int>> p1(dq.begin(),dq.end());
    p1.pop();
    p1.push(0);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章