博客
关于我
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中提示:UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position
    查看>>
    python中数据类型存储_浅谈Python中的数据类型
    查看>>
    python中文件最重要的功能是什么-学 Python 都用来干嘛的?
    查看>>
    python中文版语言_高盛最新调查:Python超过汉语成为未来最重要技能,你准备学哪种编程语言?...
    查看>>
    Python中文问题SyntaxError
    查看>>
    Python中方括号和括号括起来的列表有什么区别?
    查看>>
    python中时间处理_Python中处理时间的几种方法小结
    查看>>
    Python中枚举串口(包括虚拟端口)的跨平台方法是什么?
    查看>>
    python中根号下a怎么写_python中根号怎么表示
    查看>>
    Python中正则表达式的巧妙使用
    查看>>
    Python中浮点数的二进制表示(位不是十六进制)
    查看>>
    Python中特殊函数和表达式 filter,map,reduce,lambda
    查看>>
    python中用socket检测端口_Python 用socket模块实现检测端口和检测web服务
    查看>>
    python中用于列表操作的plus和append有什么区别?
    查看>>
    python中用递归求和
    查看>>
    python中的@staticmethod
    查看>>
    python中的array函数作用_NumPy 数组使用大全
    查看>>
    python中的isinstance判断多个对象类型
    查看>>
    python中的keys、values、items
    查看>>
    Python中的lambda和apply结合使用
    查看>>