目录

queue的简单介绍

queue的使用

queue()

push()

pop()

empty()

size()

front()

back()

swap()

queue的模拟实现

成员变量

成员函数

bool empty() const

size_t size() const

const T& front() const

T& front()

const T& back() const

T& back()

void push(const T& x)

void pop()

完整代码

queue.h

测试代码

总结


queue的简单介绍

以前我用c语言模拟实现过queue,也写过相关的博客,在这里不给各位老铁回顾queue的特征了~

队列的模拟实现(单链链表模拟)_暴走的橙子~的博客-CSDN博客

在这里我们来翻译一下C++文档来了解一下:

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。(尾插,头删)
2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列
4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

queue的使用

queue()

构造空的队列。

const container_type& ctnr = container_type():这是一个空间适配器,我们只需要知道有了它就可以高效申请释放空间就可以了。

举个栗子:

int main()
{queue<int> q;return 0;
}

我们来调试一下看看情况:

通过调试我们发现无参构造的对象q,是一个空队列,里面没有数据。

queue<int> q:我们在构造对象时,要在queue后面加一个<类型>,在这里指定类型是int,说明该队列里面存放的是int类型的数据。 注意:q后面不能加()

push()

将元素val插入到队尾。

举个栗子:

int main()
{queue<int> q;q.push(1);q.push(2);q.push(3);return 0;
}

我们来调试一下看看情况:

通过数组下标我们发现数据1 2 3依次从队尾插入进去了。

我们画图来展示一下这个过程:

pop()

将队头的元素val进行删除(哨兵位头结点除外)。

举个栗子:

int main()
{queue<int> q;q.push(1);q.push(2);q.push(3);q.pop();q.pop();return 0;
}

我们调试一下看看这个过程:

我们发现,每次pop(),就把队头的数据删除了,第一次pop(),删除了数据1,第二次pop()删除了数据2。

我们画图来展示一下这个过程:

empty()

判断队列是否为空。如果为空就返回真(1),如果不为空就返回假(0)。

举个栗子:

int main()
{queue<int> q1;q1.push(1);q1.push(2);q1.push(3);cout << q1.empty() << endl;queue<int> q2;cout << q2.empty() << endl;return 0;
}

运行结果:

我们发现q1队列中有数据,所以就返回假。q2是一个空队列,于是就返回真。

size()

返回队列中元素的个数。

举个栗子:

int main()
{queue<int> q1;q1.push(1);q1.push(2);q1.push(3);cout << q1.size() << endl;queue<int> q2;cout << q2.size() << endl;return 0;
}

运行结果:

front()

返回队列中队头元素的引用。

举个栗子:

int main()
{queue<int> q1;q1.push(1);q1.push(2);q1.push(3);cout << q1.front() << endl;int& p = q1.front();p = 10;cout << q1.front() << endl;return 0;
}

运行结果:

我们发现第一次输出是取到了队头的数据。

并且我们知道返回的是队头数据的引用,那么是否可以修改呢?

我们通过int& p来接收返回值并修改,发现对头的数据的确被修改了!

注意:如果我们将来用引用变量接收了队头的返回值,我们为防止误操作把队头数据修改了,我们最好用const int& p来修饰。

back()

返回队尾中数据的引用。

举个栗子:

int main()
{queue<int> q1;q1.push(1);q1.push(2);q1.push(3);cout << q1.back() << endl;int& p = q1.back();p = 30;cout << q1.back() << endl;return 0;
}

运行结果:

我们发现第一次输出是取到了队尾的数据。

并且我们知道返回的是队尾数据的引用,那么是否可以修改呢?

我们通过int& p来接收返回值并修改,发现对头的数据的确被修改了!

注意:如果我们将来用引用变量接收了队尾的返回值,我们为防止误操作把队尾数据修改了,我们最好用const int& p来修饰。

swap()

交换两个队列中的数据。

举个栗子:

int main()
{queue<int> q1;q1.push(1);q1.push(2);q1.push(3);queue<int> q2;q2.push(10);q2.push(20);q2.push(30);q1.swap(q2);while (!q1.empty()){cout << q1.front() << " ";q1.pop();}cout << endl;while (!q2.empty()){cout << q2.front() << " ";q2.pop();}return 0;
}

运行结果:

我们发现q1原来的数据时1 2 3;q2原来的数据是10 20 30。

经过q1.swap(q2)后我们发现q1里面的数据是10 20 30。q2里面的数据是1 2 3

注意:这里的swap不是算法库里面的,而是queue里面的成员函数~

queue的模拟实现

成员变量

template<class T,class Container = deque<T>>
private:
Container _con;

//第二个模板参数给一个缺省值(缺省值从右往左给)

template<class T,class Container = deque<T>>:Container是一个容器适配器,在这里我们默认使用deque<T>这样的容器。

_con:构造的指定容器的一个对象。模板参数是直接用,不可以Container<T>这样来操作。

这里的容器适配器也可以使用list<T>来代替。适配的容器只要支持queue内部实现方法对应的接口即可。

成员函数

bool empty() const

bool empty() const
{return _con.empty();
}

bool empty() const //判断队列是否为空
{
    return _con.empty();//调用适配的容器的empty()的函数接口。
}

size_t size() const

size_t size() const
{return _con.size();
}

size_t size() const 
{
    return _con.size(); //调用_con容器的size()的函数接口。
}

const T& front() const

const T& front() const
{return _con.front();
}

const T& front() const  //返回头部数据的引用,由于被const修饰,所以不能被修改
{
    return _con.front(); //调用适配的容器的front()接口。_con适配的容器一定要有支持这样的接口。
}

T& front()

T& front()
{return _con.front();
}

T& front()  //与上面的函数构成函数重载,在这里返回的val值可以被修改
{
    return _con.front();
}

const T& back() const

const T& back() const
{return _con.back();
}

const T& back() const //返回尾部数据的引用,由于被const修饰,所以不能被修改
{
    return _con.back();//调用适配的容器的back()接口。_con适配的容器一定要有支持这样的接口。
}

T& back()

T& back()
{return _con.back();
}

T& back() //与上面的函数构成函数重载,在这里返回的val值可以被修改
{
    return _con.back();
}

void push(const T& x)

void push(const T& x)
{_con.push_back(x);
}

void push(const T& x) 
{
    _con.push_back(x);//往尾部插入数据,适配的容器要支持push_back()这样的函数接口
}

void pop()

void pop()
{_con.pop_front();
}

void pop()
{
    _con.pop_front(); //删除头部数据,_con容器要支持头删这样的函数接口。像list就可以。

注意:vector不支持pop_front()、push_front(),所以不能当queue适配的容器。
}

完整代码

queue.h

#pragma once
#include<deque>
#include<iostream>
using namespace std;namespace cyq
{template<class T,class Container = deque<T>>class queue{public:bool empty() const{return _con.empty();}size_t size() const{return _con.size();}const T& front() const{return _con.front();}T& front() {return _con.front();}const T& back() const{return _con.back();}T& back(){return _con.back();}void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}private:Container _con;};
}

测试代码

int main()
{cyq::queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);cout << q.size() << endl;cout << "队尾数据:" << q.back() << endl;while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;return 0;
}

运行结果:

总结

        我们发现C++中stack和queue的模拟实现都使用了容器适配器,很好地体现了复用的原则。通过模板可以让编译器自动推导存储的数据类型,这体现了泛型编程的特点。

可以通过与C语言中模拟实现队列来进行比较,看看其中代码的差距体现。在最上面有博客的链接~

1、queue是先进先出的规则,它不支持迭代器!所以也就不支持范围for(语法糖),和stack一样。

2、我们可以构造的方式:

queue<int,deque<int>> q; //使用deque容器

queue<int,list<int>> q; //使用list容器

3、我们发现我们模拟实现的queue没有自己实现构造函数,这样可以吗?答案是可以的。这里我们不需要自己显示实现构造函数,使用编译器默认生成的就可以。因为编译器默认生成的构造函数会自动调用适配的容器里面的构造函数(调用自定义类型的构造函数)。如果老铁们对这个知识点不理解,可以看一下我之前写的C++关于类和对象博客~ stack也是同理~

看到这里,给博主支持一下吧~

C++ queue的使用及模拟实现相关推荐

  1. 【POJ2259】Team Queue(队列,模拟)

    problem 有n个小组,进行排队. 当一个人来到队伍时,若队伍中有自己小组成员时,他就直接站到其后面 如果没有,则站到队伍最后面,形成自己小组的第一个入队元素. 出队列时,给出出队指令,输出出队成 ...

  2. 数据结构学习笔记(三):队列(queue)

    目录 1 队列的结构形式与操作原则 2 两种顺序队列及其代码实现(Java) 2.1 简单队列 2.1.1 增删查操作的实现 2.1.2 简单队列存在的弊端 2.2 循环队列 3 链式队列及其代码实现 ...

  3. 十分钟之内实现stack和queue?容器适配器是什么?priority_queue不是队列?

    stack,queue,priority的模拟实现 文章目录 stack,queue,priority的模拟实现 一.栈和队列的特性(图解)

  4. 【160天】尚学堂高琪Java300集视频精华笔记(129)

    明天开始,专栏增加一个黑马程序员的课程更新. 其它容器收尾讲解 队列Queue与Deque(单向队列与双向队列) Enumeration(较老的接口,JDK1.5前使用频繁,维护旧系统会用到) Has ...

  5. java性能调优03

    1.java中的四种引用类型(级别由高到低为:强引用,软引用,弱引用和虚引用) 1.1 强引用:默认创建的变量都是强引用,垃圾回收机制不会将其回收,当内存空 间不足,Java虚拟机宁愿抛出OutOfM ...

  6. 剑指offer:从上往下打印二叉树

    文章目录 分析 来源 分析 思路 典型的bfs模板题,这里使用STL中的queue,没用数组模拟队列. STL的思路:初始化队列时,根root入队:对于bfs主体过程while循环内,取队头元素,队头 ...

  7. Python多线程原理与实现

    Date: 2019-06-04 Author: Sun Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了解线程池的使用 1 线程基本 ...

  8. 这可能是最简单又有效的自监督学习方法了

    文 | 王珣@知乎 本文已获作者授权,禁止二次转载 从Kaiming的MoCo和Hinton组Chen Ting的SimCLR开始,自监督学习(SSL)成了计算机视觉的热潮显学.凡是大佬大组(Kaim ...

  9. Linux系统编程:使用semaphore信号量和mutex互斥量实现多个生产者和消费者模型

    代码实现 如题,使用semaphore信号量和mutex互斥量实现多个生产者和消费者模型.本来是想只用信号量实现生产者消费者模型的,但是发现 只能在一个生产者和一个消费者之间,要在多个生产者和消费者模 ...

最新文章

  1. 限流降级神器-哨兵(sentinel)原理分析
  2. NAS之旅--基于centos7搭建netatalk Mac TimeMachine 备份与共享服务器
  3. Windows8.1+Eclipse搭建Hadoop2.7.2本地模式开发环境
  4. Dojo EnhancedGrid Pagination
  5. c#10中的namespace
  6. AVS 帧内预测模式的汇编优化
  7. iOS开发CAAnimation详解
  8. 人工智能数学基础之高等数学
  9. 洛谷P1134 阶乘问题[数论]
  10. 打开PDF时显示please wait...怎么办?没有安装pdf阅读器经常出现的提示信息
  11. Mac好用的截图工具:Snipaste
  12. 大数据平台自动化运维,数据中心运维平台
  13. linux exchange 账号,linux exchange服务器配置
  14. linux系统端口说明
  15. IE7、IE6和火狐兼容性问题
  16. 计算机网络日志保存时间,在网络安全等级保护制度中,网络运营者应当保留网络日志不少于( )...
  17. 钓鱼攻击(kali,花生壳)
  18. 用技巧] Http请求偶尔超时+总结各种超时死掉的可能和相应的解决办法
  19. 制作minist格式的图像数据集
  20. 『推荐』一款让搜索更快捷的油猴脚本

热门文章

  1. 生成一段python代码,实现图像识别
  2. 用c语言制作药材标准数据库,自己写的一个简单的数据库...完整开源...
  3. 3ds max安装需要注意的方面
  4. 【整点没用的】软件工程基本原则在《异星工厂》中的应用
  5. Terraform 实践
  6. 走进音视频的世界——Opus编解码协议
  7. 解决Mac升级偏好设置上的小红点还在的问题
  8. 摄像头 - Camera sensor 基本知识
  9. 华为真的注册鸿蒙,熙伦国际:“鸿蒙”真的来了!华为注册了整本山海经?
  10. 知识体系:计算机知识体系