本文共 4474 字,大约阅读时间需要 14 分钟。
栈和队列的常用接口
栈和队列是C++标准库中非常常用的数据结构,它们分别提供了基于先进后出和先进先出的操作接口。这些接口是通过容器适配器实现的,实际底层使用的是双端队列(deque)来完成操作。容器适配器
容器适配器是一种设计模式,用于将一个类的接口转换为客户端期望的另一种接口。stack和queue就是一个容器适配器的例子,它们分别对deque进行了包装。默认情况下,stack和queue的底层实现都是基于deque。双端队列(deque)的设计初衷是取代vector和list,但最终未能达到预期效果,被认为是一种失败的设计。
有一句笑话是,如果你想对deque进行排序,最好的方法是将deque中的数据拷贝到一个vector中排序后再放回deque,这种做法充分说明了deque随机访问的效率低下。双端队列是什么
双端队列是一个双端开放的“连续”空间数据结构,它支持O(1)复杂度的头尾操作。它既不完全是队列,也不完全是vector或list,而是vector和list的结合体。与vector相比,deque在头部操作不需要移动元素;与list相比,deque的缓存命中率较高。然而,deque并不是真正的连续空间结构,而是由多个小块连续的空间拼接而成,类似于动态增长的二维数组。双端队列的优缺点
优点:缺点:
deque作为stack和queue底层数据结构的优势
总结
要设计一个既有vector的优点又有list的优点的数据结构,就有deque。但在C++中,这种完美的数据结构并不存在。C++是一门注重效率的语言,因此实际应用中并未广泛使用deque。stack模拟实现
template> class stack {public: stack() {} bool empty() const { return _con.empty(); } size_t size() const { return _con.size(); } const T& top() const { return _con.back(); } void push(const T& x) { _con.push_back(x); } void pop() { _con.pop_back(); }private: Container _con;};
queue模拟实现
template> class queue {public: queue() {} bool empty() const { return _con.empty(); } size_t size() const { return _con.size(); } const T& front() const { return _con.front(); } const T& back() const { return _con.back(); } void push(const T& x) { _con.push_back(x); } void pop() { _con.pop_front(); }private: Container _con;};
仿函数
仿函数(functor)是一个类,通过重载operator()实现功能,与函数调用方式相似。仿函数广泛用于模板参数的推演,例如排序和比较操作。仿函数的应用场景
仿函数可以通过传递不同的比较逻辑来实现不同的行为。例如:优先级队列
优先级队列是一种支持快速获取最大或最小元素的队列,通常用于事件调度或任务优先级管理。其底层实现通常是vector加上堆算法。优先级队列的关键点:优先级队列模拟实现
#include#include #include #include namespace my { template , class Compare = greater > class priority_queue { public: void ShiftDown(size_t parent) { Compare com; size_t child = parent * 2 + 1; while (child < _con.size()) { if (child + 1 < _con.size() && com(_con[child+1], _con[child])) { child++; } if (com(_con[child], _con[parent])) { swap(_con[child], _con[parent]); } else { break; } parent = child; child = 2 * parent + 1; } } void ShiftUp(size_t child) { Compare com; size_t parent = (child - 1) / 2; while (child > 0) { if (com(_con[child], _con[parent])) { swap(_con[child], _con[parent]); } else { break; } parent = (child - 1) / 2; child = parent; } } priority_queue() = default; template priority_queue(InputIterator first, InputIterator last) : _con(first, last) { for (size_t i = 1; i < _con.size(); ++i) { ShiftUp(i); } } bool empty() const { return _con.empty(); } size_t size() const { return _con.size(); } const T& top() const { return _con.front(); } void push(const T& x) { _con.push_back(x); ShiftUp(_con.size() - 1); } void pop() { assert(!_con.empty()); swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); ShiftDown(0); } private: Container _con; };}
#include#include #include #include namespace my { template , class Compare = greater > class priority_queue { public: void ShiftDown(size_t parent) { Compare com; size_t child = parent * 2 + 1; while (child < _con.size()) { if (child + 1 < _con.size() && com(_con[child+1] , _con[child])) child++; if (com(_con[child] , _con[parent])) swap(_con[child], _con[parent]); else break; parent = child; child = 2 * parent + 1; } } void ShiftUp(size_t child) { Compare com; size_t parent = (child - 1) / 2; while (child > 0) { if (com(_con[child] , _con[parent])) swap(_con[child], _con[parent]); else break; parent = (child - 1) / 2; child = parent; } } priority_queue() = default; template priority_queue(InputIterator first, InputIterator last) : _con(first, last) { for (size_t i = (_con.size() - 2) / 2; i >= 0; i--) ShiftDown(i); } bool empty() const { return _con.empty(); } const size_t size() const { return _con.size(); } const T& top() const { return _con.front(); } void push(const T& x) { _con.push_back(x); ShiftUp(_con.size()-1); } void pop() { assert(!_con.empty()); swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); ShiftDown(0); } private: Container _con; };}
转载地址:http://ghse.baihongyu.com/