一、stack的介绍
1、什么是stack(栈)?
(1)stack是一种容器适配器(配接器),用在先进后出情境下,只能在容器的一端进行插入和删除操作。
(2)stack作为容器适配器,是对特定的类进行封装作为其底层容器,并提供一组特定的成员函数来访问其元素。
(3)stack支持任何标准容器类模板,或者一些特定类作为底层容器。不过一定要支持判空、获取尾部元素,尾插、尾删操作
(4)vector、list、deque具备上述功能,当没有指定stack的底层特定容器,默认情况下使用deque
2、stack的基本使用
(1)构造:stack(const container_type & ctnr=container_type())
(2)判空:bool empty()const
(3)返回有效元素个数:size_type size()const
(4)返回栈顶元素:value_type& top()const
(5)压栈:void push(const value_type&val);
(6)弹栈:void pop();
(7)交换:void swap(stack& x);
emplace:在栈顶构造新元素
二、queue的介绍
1、什么是队列?
(1)队列是一种容器适配器,在先进先出的环境下进行操作,从容器一端插入,另一端删除。
(2)元素从队尾入列,队头出列
(3)queue的底层容器应该支持以下操作:
判空、size、返回队头和队尾元素、队尾插入、队头删除。
(4)deque和list满足要求,一般情况下,用deque作为底层容器。
2、queue的基本操作
三、priority_queue的介绍
1、什么是priority_queue?
(1)优先队列也是一种容器适配器,它的第一个元素总是其元素中最大元素,并严格按照大小排序。
(2)它类似堆,可以随时插入元素,并且可以检索到最大堆元素
(3)成为priority_queue的基本待满足条件:
- empty():判空
- size():返回容器中有效元素个数
- front():返回容器中第一个元素
- push_back():容器尾部插入元素
- pop_back():删除容器尾部元素
(4)vector和deque满足要求,默认情况下,一般使用vector作为priority_queue的底层容器。
(5)要支持迭代器随机访问,且在某些情况下会自动调用算法函数make_heap、push_heap和pop_heap自动来完成操作。
2、priority_queue的基本使用
优先队列默认使用vector作为底层容器,在vector上又使用了堆算法将vector中的元素构造成堆的结构,且priority_queue默认是大堆。
#include<iostream>
#include<queue>//priority_queue需要包含的头文件
#include<vector>
#include<functional>//greater算法的头文件,默认是大堆
using namespace std;
void test()
{
priority_queue<int>q;//默认是大堆 less
vector<int>v = { 1, 2, 3, 4, 5, 6, 7 };
priority_queue<int>a(v.begin(), v.end());
while (!a.empty())
{
cout << a.top()<<" ";
a.pop();
}
cout << endl;//结果:7,6,5,4,3,2,1
a.push(10);
a.push(0);
a.push(1);
a.push(1);//可以有相同元素的存在
while (!a.empty())
{
cout << a.top() << " ";
a.pop();
}
cout << endl;
//建小堆
priority_queue<int, vector<int>, greater<int>>b(v.begin(),v.end());//小堆
while (!b.empty())
{
cout << b.top() << " ";
b.pop();
}
cout << endl;
priority_queue<int, vector<int>, less<int>>c(v.begin(), v.end());//默认大堆
while (!c.empty())
{
cout << c.top() << " ";
c.pop();
}
cout << endl;
}
(1)构造空的队列:
注意这里的参数顺序,priority_queue<int, vector<int>, greater<int>>b(v.begin(),v.end());
(2)判空:bool empty()const
(3)返回堆顶元素:const value_type& top()const
(4)插入:void push(const T& x)
(5)删除:void pop()
(6)建小根堆,将第三个参数改为greater
- 如果在priority_queue中放自定义类型的数据,用户需要在自定义类里面重载小于<或者大于>号(主要根据其是大或小堆来定)
- 也可自己定义比较函数,在存入的是自定义类型情况下需要自己定义比较规则(仿函数,小括号的重载)
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);
}
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 TestPriorityQueue()
{
// 自己定制比较的规则
priority_queue<Date*, vector<Date*>, Less> q;
q.push(&Date(2018, 10, 29));
q.push(&Date(2018, 10, 28));
q.push(&Date(2018, 10, 30));
cout << *q.top() << endl;
}
四、容器适配器
1、什么是适配器?
适配器是一种设计模式,可以将一个类的接口转换为客户希望的另一个接口。
2、为什么stack、queue、priority_queue是容器适配器而不是容器呢?
因为每个容器在底层都有自己的实现方式,但是stack、queue、priority_queue在底层只是将其他容器进行了封装得到的。
比如:stack是对deque的封装,queue是对deque的封装,priority_queue是对vector的封装
//stack
template<class T,class Container=deque<T>> class stack;
//queue
template<class T,class Container=deque<T> > class queue;
//priority_queue
template<class T,class Container=vector<T>>,
class Compare=less<typename Container::value_type>>class priority_queue;
3、为什么选择deque作为stack和queue的底层默认容器?
(1)stack和queue没有迭代器,不需要遍历,只需要在固定一段或两端进行操作。
(2)stack在增长时,deque比vector的效率高;queue中元素在增长的时候,deque不仅效率比list高,而且内存利用率也高