博客
关于我
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/

    你可能感兴趣的文章
    Python编程基础(附Pycharm与开发环境)
    查看>>
    python 如何“否定“value : 如果为真则返回假,如果为假则返回真
    查看>>
    Python 如何在 Web 环境中使用 Matplotlib 进行数据可视化
    查看>>
    python 如何把字符串转换成浮点数
    查看>>
    python 如果文件夹不存在就创建文件夹
    查看>>
    Python 如果有很多或以收缩形式
    查看>>
    Python 子进程 Popen 与 Pyinstaller
    查看>>
    Python 子进程 Popen.communicate() 等价于 Popen.stdout.read()?
    查看>>
    Python 子进程 Popen:为什么会出现“ls *.txt“?不行?
    查看>>
    Python 子进程参数
    查看>>
    python 字典 key 和value 互换
    查看>>
    Python 字典 vs If 语句速度
    查看>>
    python 字典sorted自定义排序,按照key or value排序
    查看>>
    python 字典和列表区别_元组列表和字典的主要区别是什么?
    查看>>
    python 字符串中特定字符替换,截取
    查看>>
    Python 字符串总结
    查看>>
    python 字符串显示中文_Python字符串开头的b"、u"、r"与中文乱码
    查看>>
    Python 字符串的几种拼装方式
    查看>>
    python 存入数据库bigint_python基础_MySQL的bigint类型
    查看>>
    python 学习 面向对象编程
    查看>>