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

    你可能感兴趣的文章
    Oracle学习总结(8)—— 面向程序员的数据库访问性能优化法则
    查看>>
    Oracle学习总结(9)—— Oracle 常用的基本操作
    查看>>
    oracle学习笔记《二》
    查看>>
    oracle学习笔记(4)
    查看>>
    Oracle学习第二天---Profile的使用
    查看>>
    Oracle学习第五课
    查看>>
    Oracle安全攻防,你可能不知道自己一直在裸奔
    查看>>
    Oracle安装、Navicat for Oracle、JDBCl连接、获取表结构
    查看>>
    Oracle安装与远程连接配置(附Oracle安装包)
    查看>>
    Oracle官方推荐的性能测试工具!简单、精准又直观!
    查看>>
    ORACLE客户端连接
    查看>>
    oracle密码包含,【扫盲】Oracle用户密码含有特殊字符的处理办法
    查看>>
    ubuntu完美搭建git服务器【转】
    查看>>
    Oracle导入导出命令
    查看>>
    oracle导出
    查看>>
    oracle常用SQL——创建用户、表空间、授权(12C)
    查看>>
    Oracle常用函数整理
    查看>>
    Oracle常用查询语句
    查看>>
    oracle常用的一些sql命令
    查看>>
    oracle常用知识,Oracle常用知识点记录
    查看>>