适配器是一种设计模式,将一个类的接口转换为另外一个类接口。在 stl 中,常见的容器适配器有 stack、queue 和 priority_queue。容器适配器就是将特定容器类封装作为其底层容器类。
在标准 stl 中,stack和queue默认底层容器都是deque。其实作为容器适配器,底层可以是任意的标准容器类模板之一,如果没有实例化指定底层容器,底层都默认是deque。他们只支持栈顶或者队头队尾进行操作,不能遍历,所有没有维护迭代器。
优先级队列 priority_queue,相当于堆。那么对于 priority_queue的底层容器,要能实现随机访问和迭代器。满足要求的标准容器类有 vector 和 deque。默认情况下,如果没有为特定的 priority_queue 类实例化指定容器类,则使用 vector。
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构。默认情况下priority_queue是大堆。
为什么 stack 和 queue 默认底层容器使用 deque?
stack是一种后进先出的特殊线性数据结构,因此只要具有 push_back() 和 pop_back() 操作的线性结构,都可以作为stack的底层容器,比如 vector 和 list 都可以;queue 是先进先出的特殊线性数据结构,只要具有 push_back 和 pop_front 操作的线性结构,都可以作为 queue 的底层容器,比如 list。但是 STL 中对 stack 和 queue 默认选择 deque 作为其底层容器,主要是因为:
1. stack 和 queue 不需要遍历(因此 stack 和 queue 没有迭代器),只需要在固定的一端或者两端进行操作。
2. 在 stack 中元素增长时,deque 比 vector 的效率高;queue 中的元素增长时,deque 不仅效率高,而且内存使用率高。
我们来看一下关于 stack 的构造:
// constructing stacks
#include <iostream> // std::cout
#include <stack> // std::stack
#include <vector> // std::vector
#include <deque> // std::deque
int main ()
{
std::deque<int> mydeque (3,100); // deque with 3 elements
std::vector<int> myvector (2,200); // vector with 2 elements
std::stack<int> first; // empty stack
std::stack<int> second (mydeque); // stack initialized to copy of deque
std::stack<int,std::vector<int> > third; // empty stack using vector
std::stack<int,std::vector<int> > fourth (myvector);
return 0;
}
我们可以看出来,stack不仅可以使用deque作为底层容器来初始化构造,还可以使用 vector来当做底层容器来构造,需要在模板参数中声明。
同样的,queue 的初始化构造和 stack 类似:
// constructing queues
#include <iostream> // std::cout
#include <deque> // std::deque
#include <list> // std::list
#include <queue> // std::queue
int main ()
{
std::deque<int> mydeck (3,100); // deque with 3 elements
std::list<int> mylist (2,200); // list with 2 elements
std::queue<int> first; // empty queue
std::queue<int> second (mydeck); // queue initialized to copy of deque
std::queue<int,std::list<int> > third; // empty queue with list as underlying container
std::queue<int,std::list<int> > fourth (mylist);
return 0;
}
接下来我们来模拟实现 stack 和 queue:(之前我曾经写过一篇博客,也是模拟实现stack 和 queue,只不过底层使用的是 动态顺序表和链表,博客链接:https://blog.youkuaiyun.com/smx_dd/article/details/83243878)
#include<iostream>
#include<deque>
using namespace std;
template<class T,class Container=deque<T>>
class stack
{
public:
void push(const T& x)
{
con.push_back(x);
}
void pop()
{
con.pop_back();
}
size_t size()
{
return con.size();
}
bool empty()
{
return con.empty();
}
T& top()
{
return con.back();
}
const T& top() const
{
return con.back();
}
private:
Container con;
};
template<class T,class Container=deque<T>>
class queue
{
public:
void push(const T& x)
{
con.push_back(x);
}
void pop()
{
con.pop_front();
}
size_t size()
{
return con.size();
}
bool empty()
{
return con.empty();
}
T& front()
{
return con.front();
}
const T& front() const
{
return con.front();
}
T& back()
{
return con.back();
}
const T& back() const
{
return con.back();
}
private:
Container con;
};
int main()
{
stack<int> s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
cout<<s.size()<<endl;
cout<<s.top()<<endl;
s.pop();
s.pop();
cout<<s.size()<<endl;
cout<<s.top()<<endl;
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
q.push(5);
cout << q.size() << endl;
cout << q.front() << endl;
cout << q.back() << endl;
q.pop();
q.pop();
cout << q.size() << endl;
cout << q.front() << endl;
cout << q.back() << endl;
return 0;
}
程序运行结果: