特色:先進先出
成員函數:
stack()--構造
empty()--判空
size() --求個數
top() --返回棧頂元素
push --壓棧
pop() --出棧設計模式
應用less
由於棧中最小值是隨push和pop操做變化的,進棧時min會更新,出棧min也可能會更新,因此每一個元素進棧時當前棧中最小值應該被保存下來ide
// 法一: 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(); } };
在樹的遍歷中,也會用到棧,必定要練題!spa
特色:先進後出
成員函數:
queue()--構造
empty()--判空
size() --求個數
front()--返回隊頭元素
back() --返回隊尾元素
push --壓棧
pop() --出棧設計
在此介紹一種很重要的隊列叫作優先隊列指針
優先級隊列是按照優先級來處理數據的,會將隊列中按優先級來排序出隊。通常是藉助堆來選出優先級高的元素
按照堆的順序存儲元素,默認是經過vector容器來存儲的
他所用的函數模板是:code
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); }