当前课程知识点:C++语言程序设计进阶 > 第九章 模板与群体数据 > 队列 > 队列类模板
队列是只能向一端添加元素,从另一端删除元素的线性群体
队空
队满
一般状态
队列中没有元素(以数组容纳的队列为例)
队列中元素个数达到上限(以数组容纳的队列为例)
队列中有元素,但未达到队满状态(以数组容纳的队列为例)
在想象中将数组弯曲成环形,元素出队时,后继元素不移动,每当队尾达到数组最后一个元素时,便再回到数组开头。
//Queue.h #ifndef QUEUE_H #define QUEUE_H #include <cassert> //类模板的定义 template <class T, int SIZE = 50> class Queue { private: int front, rear, count; //队头指针、队尾指针、元素个数 T list[SIZE]; //队列元素数组 public: Queue(); //构造函数,初始化队头指针、队尾指针、元素个数 void insert(const T &item); //新元素入队 T remove(); //元素出队 void clear(); //清空队列 const T &getFront() const; //访问队首元素 //测试队列状态 int getLength() const;//求队列长度 bool isEmpty() const;//判断队列空否 bool isFull() const;//判断队列满否 }; //构造函数,初始化队头指针、队尾指针、元素个数 template <class T, int SIZE> Queue<T, SIZE>::Queue() : front(0), rear(0), count(0) { } template <class T, int SIZE> void Queue<T, SIZE>::insert (const T& item) {//向队尾插入元素 assert(count != SIZE); count++; //元素个数增1 list[rear] = item; //向队尾插入元素 rear = (rear + 1) % SIZE; //队尾指针增1,用取余运算实现循环队列 } template <class T, int SIZE> T Queue<T, SIZE>::remove() { assert(count != 0); int temp = front; //记录下原先的队首指针 count--; //元素个数自减 front = (front + 1) % SIZE;//队首指针增1。取余以实现循环队列 return list[temp]; //返回首元素值 } template <class T, int SIZE> const T &Queue<T, SIZE>::getFront() const { return list[front]; } template <class T, int SIZE> int Queue<T, SIZE>::getLength() const { //返回队列元素个数 return count; } template <class T, int SIZE> bool Queue<T, SIZE>::isEmpty() const { //测试队空否 return count == 0; } template <class T, int SIZE> bool Queue<T, SIZE>::isFull() const { //测试队满否 return count == SIZE; } template <class T, int SIZE> void Queue<T, SIZE>::clear() { //清空队列 count = 0; front = 0; rear = 0; } #endif //QUEUE_H
大家好
欢迎回来继续学习
C++语言程序设计
这一节我们来学习队列类
队列也是一种线性群体
那么这种数据结构呢
它也是一种受限制的线性结构
只能从一端插入数据
而从另一端删除数据
插入一数据的一端叫做队尾
删除数据的一端叫做队头
实际上就是跟我们
人去买东西
去银行办业务排队是一样的
就是跟着队走
它是一种先来先服务的结构
排列
也叫先进先出的结构
接下来我们来看一个
队列类的它的示意图
大家看
这是不是跟我们人排队很像
一边是队头 一边是对队尾
从队头出队
也就是取出数据 删除数据
从队尾入队
也就是说
把数据从队尾存进去
队列的基本状态呢
有是有队满 队空
和一般状态
现在我们来看看
这几种状态它们的示意图
队空状态呢
就是队里都还没有元素的时候
这个时候大把的空间
随便地用
可以入队
但是出队就不行了
因为没有人排到队里了
这是队空状态
它的队头 队尾
就指向了同样的位置
那么队满状态呢
就是它队列的空间
全部都占满了
这个时候呢
队头可以出队
但是从队尾就不能往里入队了
因为空间没有了
一般状态呢
就是队列中有元素
可以出队
也还有空间 也可以入队
我们想一想
我们人排队的时候是怎么排的呢
前面的人办完业务以后
后面的人跟着往前走 对吧
你总不能排队排在这儿不走吧
比如说一个房间很小
本来人很多
都挤满了
队都排到房子外面去了
大家假期买火车票的时候
经常遇到这样的情况 是吧
那这个时候
如果前面的人买完票
走了
但是紧挨着他们后面的人
不往前走
门口的人就不往里进
那我们老看着
这个门口都堵死了
人都满了 进不去了
但是里面呢
可能已经很松散了
买完票的人走了
没有及时跟进
这种情况
我们在排队的时候也见过
那我们得会催
前面赶紧往前走 赶紧往前走
后面这么多人进不去呢 对吧
在计算机中
我们在程序中
实现一个队列
也有这样的情况啊
当队头的元素出队以后
后面的元素要及时向前移动
出队一个元素移动一格
出队一个元素移动一格
如果出队了
后面的元素不移动
会产生什么问题呢
就是假溢出
房子里面空着呢
但是后面的人以为进不去了
都堵在门外头
那如果我们在程序中
出现那样假溢出
就导致我们无法再往队列里面
添加元素了
其实呢
队列的空间空着
可是出队一个元素移动一下
出队一个元素移动一下
是不是也挺麻烦的
这是要开销的
也就是要花时间 空间开销
去移动这些元素
我们考虑到程序的效率呢
又希望能不能有元素出队了
我们不移动元素呢
也有这种办法
我们可以采用循环队列
把内存空间想象成一个弯曲的
队头 队尾连接起来
这样就可以不移动元素了
转着圈用这个内存空间
我们下面通过示意图来看一看
那么
我们看这个示意图呢
就是每当队尾
达到数组的最后一个元素的时候
就再回到数组开头去使用
那么这种弯曲成圆环状的
是模拟我们使用数组
来存放队列的情况
如果我们用链表来存放元素呢
当然就没有移动元素
这样一个问题了
大家回去可以试一试
自己写个程序
用链表来生成一个队列
是不是就没有这种假溢出
移动的问题了
那么用数组的话
我们在想象中把它弯曲出来
其实也很简单的
就是队尾和队头
都是各自往自己的行进方向去走
只要还有空间
就可以往里放
如果队头队尾到一块了
那么到底是队空了
还是队满了呢
这个时候最简单的办法
我们可以用计数的方式
看看可以有多少个元素了
元素个数达到上限了
就说明是队满了
如果元素个数是0
就说明是队空了
那也有的算法实现的时候呢
去区分到底是队头
从后面追上了队尾
还是队尾从后面追上了队头
那么这样也可以来区分
所以大家去
实现这个队列的时候呢
可以自己选一种觉得合适的算法
接下来的这个例题
就实现了一个队列类模板的代码
我们一起来看一下
这是一个简单的队列类模板程序
说它是个简单程序
因为简化了很多环节
功能也非常有限
包括数据合法性检查
是不是满
是不是空的判断呢
这些都是一种简化的方式
只是为了给大家看一看
这个队列的实现的原理
作为一个示例
看这个类模板呢
它也是有类型参数
还有这个常量SIZE
SIZE是作为这个队列的容量
然后它的数据有头指针
尾指针
以及元素个数
元素个数呢
指的是队列之中
它实际的元素个数
而SIZE呢
指的是它的总的容量
那么函数呢包括构造函数
新元素入队的函数
元素出队的函数
以及清空队列
还有读取
有就是访问队首元素
但是读取了以后呢
并不删除它
这个求队列长度
判断队是否空
判断队是否满
好 我们来看函数的实现
构造函数很简单
做一下初始化
然后新元素入队呢
看到是插在队尾
这时候还要判断
205za
00:06:58,040 --> 00:06:59,200
队是不是满了
队不满的情况下
元素个数加1
然后向队尾插入一个元素
这个时候呢队尾
它的指针
它的下标要加1
加1以后还要除以SIZE取余
说明这个模板
实现的是一个循环队列
然后再看出队
那判断队是否空
不空的情况下呢
记录下现在的队首元素的下标
简称队首指针
那它并不是一个
真正的指针类型的指针
又指向它的位置
实际上是队首元素的下标
然后总的元素个数减1
然后将队首元素的下标加1以后
也是要除以SIZE取余
实现循环队列
最后用暂存的这个temp作下标
返回以前旧的那个队首
位置那个元素
这就是一个元素出队了
那么getFront是访问
是访问
也就是读取队首元素
直接返回队首元素就行了
它并不删除它
这个getLength函数呢
是返回队列的元素个数
直接return count就可以了
这个isEmpty判断队列是否空
count是否等于0
isFull判断count是否等于SIZE
它是否满
然后clear就是把所有的状态
恢复到初始状态
就是清空了队列
这就是一个简单的
队列类模板的代码
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义