特色:先进先出
成员函数:
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); }