1. 容器适配器
1.1 什么是适配器
适配器器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该中模式是将一个类的接口转换成客户希望的另外一个接口。
1.2 为什么将stack、queue和priority_queue称作为容器适配器
虽然stack、queue、priority_queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为每个容器在底层都有自己的实现方式,而stack、queue、priority_queue只是在底层将其他容器进行了封装,比如:
2. stack的模拟实现
#include<deque>
template<class T, class Con = deque<T>>
class Stack
{
public:
Stack() {}
void Push(const T& x) {_c.push_back(x);}
void Pop() {_c.pop_back();}
T& Top() {return _c.back();}
const T& Top()const {return _c.back();}
size_t Size()const {return _c.size();}
bool Empty()const {return _c.empty();}
private:
Con _c;
};
void TestStack()
{
// 适配体现在第二个模板参数可以使用不同的容器,然后适配生成的stack效果是一样的。
//Stack<int, deque<int>> s;
//Stack<int, vector<int>> s;
//Stack<int, list<int>> s;
Stack<int> s;
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
cout << s.Size() << endl;
cout << s.Top() << endl;
s.Pop();
s.Pop();
cout << s.Size() << endl;
cout << s.Top() << endl;
}
3. queue的模拟实现
#include<deque>
template<class T, class Con = deque<T>>
class Queue
{
public:
Queue() {}
void Push(const T& x) {_c.push_back(x);}
void Pop() {_c.pop_front();}
T& Back() {return _c.back();}
const T& Back()const {return _c.back();}
T& Front() {return _c.front();}
const T& Front()const {return _c.front();}
size_t Size()const {return _c.size();}
bool Empty()const {return _c.empty();}
private:
Con _c;
};
void TestQueue()
{
// 适配体现在第二个模板参数可以使用不同的容器,然后适配生成的queue效果是一样的。
//Queue<int, deque<int>> q;
//Queue<int, list<int>> q;
Queue<int> q;
q.Push(1);
q.Push(2);
q.Push(3);
q.Push(4);
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;
}
4. 为什么选择deque作为stack和queue的底层默认容器
stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:
1.stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。deque作为在两端插入删除最快,没有之一(足矣),list还需要进行申请节点操作,释放节点操作都是单个操作,而deque是一块一块的进行申请及释放的。double ended queue。
2. 在stack中元素增长时,deque比vector的效率高;queue中的元素增长时,deque不仅效率高,而且内
存使用率高。
3.并且在使用stack及queue时是基本忽视迭代器操作的,直接采用接口进行。而deque的迭代器很慢且很复杂,即规避了这一个缺点。
综上三点所述:deque的劣势全被忽略,而优势被放大。deque理所应当作为stack、queue的底层默认容器。
5. 总结
配接器:
stack
queue
priority_queue
stack:
默认适配器:deque
可选适配器:vector list
push => push_back
pop => pop_back
top => back
queue:
默认适配器:deque
可选适配器:list
push => push_back
pop => pop_front
back => back
front=> front
priority_queue:
#include < functional> (仿函数)
默认适配器:vector
默认比较方式:less
可选适配器:deque
可选比较方式:greater
#include < algorithm> (算法)
构造 => make_heap
push => push_back + push_heap
pop => pop_front + pop_heap
top => front
仿函数:可以当成函数使用的类,方法是重载函数调用运算符("()")
为什么选择deque作为queue和stack的底层:因为deque在两端进行增长和删除的速度是最快的。