棧:
特點:先進先出
成員函數:
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);
}