容器适配器 -------------- stack 、queue、priority_queue的使用以及 为什么默认使用deque作为底层容器?

什么是适配器?
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

1.为什么将stack、queue和priority_queue称作为容器适配器?
虽然stack、queue、priority_queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将 其称为容器适配器,这是因为每个容器在底层都有自己的实现方式,而stack、queue、priority_queue只是 在底层将其他容器进行了封装,比如:
1.stack 栈
可以看出stack的底层是通过封装一个容器而实现的,c++默认的容器是deque。
在这里插入图片描述
2.queue 队列
与stack相同,queue底层也是通过封装别的容器实现的。
在这里插入图片描述
3.pirority_queue 优先级队列
在这里插入图片描述
2.具体的使用
stack,和queue的使用都很简单,大家简单看一下文档就可以容易的掌握,我们这里就重点看一下**priority_queue(优先级队列)**的使用方法:

  • 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  • 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  • 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  • 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭 代器访问,并支持以下操作: empty():检测容器是否为空
    size():返回容器中有效元素个数
    front():返回容器中第一个元素的引用
    push_back():在容器尾部插入元素
    pop_back():删除容器尾部元素
  • 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指 定容器类,则使用vector。
  • 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap和pop_heap来自动完成此操作.
    2.1 priority_queue的使用
    优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成 堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。
    在这里插入图片描述
    看下面的代码了解接口用法:
#include<vector>
#include<queue>
#include<functional>

void TestPriority_queue()
{
	//默认情况下,创建的是大堆,其底层按照小于号比较
	vector<int > v{3,2,7,6,0,4,1,9,8,5};

	
	//创建q1,并将 v中数据插入到 
	priority_queue<int> q1;
	for(auto& e:v)		
	q1.push(e); 
	cout<<q1.top()<<endl;
	
	//如果要创建小堆,将第三个模板参数换成greater比较方式
	priority_queue<int,vector<int>,greater<int>> q2(v.begin(),v.end());
	cout<<q2.top()<<endl; 
 } 

注意:
1.默认情况下,priority_queue是大堆。
2. 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。
例如:有一个日期类,Date,将多个Date对象,当如priority_queue中,则需要在Date类中对 > 或者 <,进行重载。
3. 有些情况下,用户可能需要提供比较器规则
看下面的例子:

class Less
 {
 	public:
 		bool operator()(const Date* pLeft,const Date* pRight)
 		{
 			return *pLeft < *pRight;
		 }
 };
 
 void TestPriority_queue()
 {
 	//自己制定的比较规则
	 priority_queue<Date*,vector<Date*>,Less> q;
	 q.push(&Date(2019,10,11)); 
	 q.push(&Date(2019,10,12)); 
	 q.push(&Date(2019,10,13)); 
	 cout<<*q.top()<<endl;
 }

3. 为什么选择deque作为stack和queue的底层默认容器?
stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可 以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有 push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和 queue默认选择deque作为其底层容器,主要是因为:

  • stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  • 在stack中元素增长时,deque比vector的效率高;queue中的元素增长时,deque不仅效率高,而且内存使用率高。vector 当容量不够时,会开更大的空间,拷数据然后释放原来的空间,操作复杂。而deque会找另一块内存继续存放数据,效率高。
  • 相比较list,deque的插入操作会更加的高效,而且内存的使用率高,list会导致更多的内存碎片。
发布了70 篇原创文章 · 获赞 12 · 访问量 9781

猜你喜欢

转载自blog.csdn.net/lovehang99/article/details/102501427