博客
关于我
stack和queue
阅读量:350 次
发布时间:2019-03-04

本文共 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并不是真正的连续空间结构,而是由多个小块连续的空间拼接而成,类似于动态增长的二维数组。

双端队列的优缺点

优点:

  • 头部插入和删除时间复杂度为O(1),扩容效率高于vector。
  • 与list相比,deque具有较高的空间命中率,不需要额外存储空间。

缺点:

  • 由于deque由多个小块空间构成,随机访问需要大量计算边界,导致效率低下。
  • 在需要大量下标访问的操作(如排序)时,deque的效率远低于vector或list。

deque作为stack和queue底层数据结构的优势

  • stack和queue的操作仅限于头尾端口,而deque的端口操作时间复杂度为O(1),因此非常适合。
  • 与vector相比,deque在扩容时不需要数据搬移,效率更高。
  • 与list相比,deque的内存使用率更高。
  • 总结

    要设计一个既有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加上堆算法。
    优先级队列的关键点:

    • 传入Less时为大堆,传入Greater时为小堆。
    • 底层容器需要支持push_back、pop_front等操作。

    优先级队列模拟实现

    #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/

    你可能感兴趣的文章
    Node JS: < 一> 初识Node JS
    查看>>
    Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime(72)
    查看>>
    Node 裁切图片的方法
    查看>>
    Node+Express连接mysql实现增删改查
    查看>>
    node, nvm, npm,pnpm,以前简单的前端环境为什么越来越复杂
    查看>>
    Node-RED中Button按钮组件和TextInput文字输入组件的使用
    查看>>
    Node-RED中Switch开关和Dropdown选择组件的使用
    查看>>
    Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本
    查看>>
    Node-RED中使用JSON数据建立web网站
    查看>>
    Node-RED中使用json节点解析JSON数据
    查看>>
    Node-RED中使用node-random节点来实现随机数在折线图中显示
    查看>>
    Node-RED中使用node-red-browser-utils节点实现选择Windows操作系统中的文件并实现图片预览
    查看>>
    Node-RED中使用node-red-contrib-image-output节点实现图片预览
    查看>>
    Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
    查看>>
    Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
    查看>>
    Node-RED中使用range范围节点实现从一个范围对应至另一个范围
    查看>>
    Node-RED中实现HTML表单提交和获取提交的内容
    查看>>
    Node-RED中将CSV数据写入txt文件并从文件中读取解析数据
    查看>>
    Node-RED中建立TCP服务端和客户端
    查看>>
    Node-RED中建立Websocket客户端连接
    查看>>