[C++系列] 62. 容器适配器及stack、queue的模拟实现

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在两端进行增长和删除的速度是最快的。

发布了209 篇原创文章 · 获赞 42 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yl_puyu/article/details/103420919
今日推荐