9217572

当前课程知识点:数据结构 >  第3章 栈和队列 >  3.6 队列的顺序实现——循环队列 >  讲解(下)

返回《数据结构》慕课在线视频课程列表

讲解(下)在线视频

下一节:讨论

返回《数据结构》慕课在线视频列表

讲解(下)课程教案、知识点、字幕

现在,我们来看循环队列的算法实现

第一个算法,初始化

初始化要做的事情,无非是为Q分配内存

并且,为Q的各个成员赋以合适的初值

现在来看算法的实现

首先

我们用malloc函数

为队列分配连续的存储单元,将malloc的返回值赋给Q.base

因为,base这个成员指向是连续存储空间的首地址

空间不够的时候,直接退出

然后,将front的rear都初始化成0

因为我们前面约定了,front和rear重合的时候,队列为空

在初始化的时候

我们将front和rear都置成0

来表示队列为空

下一个算法,得到队列的长度

这里要注意,front和rear的相对位置

比如上面这个图,front小于rear

从front开始,沿着下标递增的方向,一直到rear

也就是绿色的2个格子,是属于队列的

另外一种情况,front大于rear

属于队列的元素

应该是从front出发

沿着下标递增的方向,到rear

除了这2个白色的格子,不属于队列之外

其他的格子,都是属于队列的元素的

下面,我们来看算法的实现

依然是分两种情况

如果front小于等于rear

那么,它的长度

应该是上面这个图的情况

我们直接拿rear减去front,就可以了

注意,不需要加1

因为,这个格子里面的内容不属于队列

这是我们前面做的约定

这种情况下,队列的长度就是rear减去front;另外一种情况

当front大于rear的时候

就是下面这个图的情况

front大于rear

绿色的格子到底有多少呢

应该是总的格子数SIZE减去白色的格子,白色的格子是

front减去rear

也不需要加1

剩下的,就是绿色的格子数

实际上

这个if-else语句

可以统一地写成一个表达式

也就是:SIZE加上rear,减去front

再模除SIZE

这个表达式是怎么得来的呢

我们分析一下

当front小于rear的时候

那么,rear减去front,是一个正数

如果我们把这个正数加上SIZE

最后

再模除SIZE

这个表达式的值

实际上跟它是一样的

因为,它是一个正数

正数

加上SIZE,再模除SIZE

那么,结果依然是这个正数,也就是rear减去front

对于下面这个表达式

我们把这个减号展开

那应该是加上rear减去front

注意

因为,这时候的front是大于rear的

所以,rear减去front是一个负数

那么,SIZE加上一个负数

这个结果,是小于SIZE的

小于SIZE的数

模除SIZE,就相当于没有模除

所以,这两个表达式,也就是

这个if-else,可以合并成这样一个表达式

第三个算法,将e入队

我们需要判断队列是否已经满了

如果满了,我们就什么都不做

因为,对于循环队列来说

我们不考虑当空间不够的时候,追加空间

这样一种情况

也就是说

当队列满了

我们什么都不做

还需要注意,当rear到达边界条件的时候,需要做一些处理

也就是,rear到达了下标最大值

应该让它的下一个值回到0,满足刚才做的环状的约定

现在,我们来看这两种情况

第一种情况,rear是小于

SIZE-1的,没有到达边界条件

这时候,直接将参数e放到rear的位置

因为,我们已经约定了,rear指向的是队尾的下一个位置

也就是入队的位置

然后,将rear加1,就可以了

当rear到达临界条件

也就是SIZE-1的时候,到达下标最大值

这时候,rear不是简单地加1

而是回到0

这个希望大家注意

现在,我们来看算法实现

我们先调用了之前的一个算法,获得队列的长度

以判断队列是否为满

如果长度等于SIZE-1

因为,rear指向的不是属于队列的元素

长度为SIZE的空间,最多

只能存放

SIZE-1个元素

所以,当长度等于SIZE-1

直接return,什么都不做

如果不是满的

我们直接将第二个参数e,赋值给rear指向的位置

下标是rear

刚才我已经说了

rear就是入队位置

入队完了之后

我们只需要将rear加1

如这两个图所示

我们应该区分为两种情况

第一种

rear小于SIZE-1的时候

rear自增就可以了

当rear等于SIZE-1的时候

我们让rear回到0

而不是简单地自增

实际上

这个if-else语句,也可以写成一个表达式

就是rear加1,模除SIZE,它的思想跟我们刚才讲的是一样的

如果rear小于SIZE-1

那么,rear加1

是小于SIZE的,小于SIZE的数模除SIZE,就相当于没有模除

就是简单地加1

如果rear等于SIZE-1,也就是这里else的情况

那么,rear加1

就等于SIZE,SIZE模除SIZE,结果是0,跟这里相对应,rear是0

我们再看下一个算法

出队,将队列Q的队头元素出队

并且,把这个元素放到e里面

我们也要判断队列是否为空

如果队列为空

没有元素可出队

那么就直接返回

同时,也要注意,front到达边界情况的处理

比如,这个图

front原来指向a1

front指向的就是队头

我们只需要将front加1,就可以了

注意,原来这个位置的元素还是a1

我们没有动它

我们也不需要动

因为,我们只需要改变front

就能够改变

哪些元素属于队列

现在,front加1之后,从front出发到rear

很明显

a1不再属于队列了

尽管

这个格子的值没有变

但现在,我们只是通过front加1

就让a1不属于队列了

实际上

这个值并没有真正被删除

这个希望大家注意。另外一种是临界情况

当front等于SIZE减1的时候

如果再将front简单地加1

那么,front会等于SIZE,越界了

我们让front回到0

以对应,这一段空间是一个环状的空间

这个约定

现在,我们来看算法的实现

我们直接给出

如果

front等于rear,代表队列为空

那么,直接return

如果队列不为空

我们直接将front指向的这个下标

它里面的值,赋值给e

因为,我们用第二个参数e,来接收被删除的队头

如果front小于

SIZE-1,front直接自增

这是一般的情况

如果front等于SIZE-1

那么,应该让front回到0

与刚才类似

这个if-else也可以写成一个表达式,front加1

模除SIZE,原因很简单

front小于SIZE-1

那么,加1是小于SIZE的

小于SIZE,再模除SIZE,就相当于没有模除

也就是这种情况

front等于SIZE-1时,front加1就等于SIZE,SIZE模除SIZE

结果是0,对应这种情况

现在,我们再来看看队列的链式存储

链队列。链队列总体上,也是一个单链表

不同的是

有两个指针

一个指针,是指向头结点

另外一个指针,是指向队尾元素

这样,可以很方便地找到一个队列

它的队头和队尾

表当中的结点,跟我们前面的单链表的结点是一致的

包含两个指针

一个是指向头结点的指针

还有一个是指向队尾元素的指针

也就是图当中的front和rear

队头元素

就是这个表达式,Q的front

是指向头结点的

一般,我们都要为单链表加一个头结点,头结点的next指向的,才是真正的队头元素

再取它的data成员

那就是队头;队尾呢

直接是rear的data

因为,rear指针指向的,就是队尾元素

直接取它的data成员,就可以了

队列

这种数据结构,是具有先进先出或者后进后出特性的,新入队的元素

总是先出队

无论是循环队列,还是链队列

前面各种算法,它们的时间复杂度都是O(1)

跟表长

是无关的,原因与栈类似

因为,我们只允许在队列的

两端进行插入、删除,不涉及到中间位置的插入、删除

所以,时间复杂度就是O(1)

队列的应用

也是比较广泛的

比如,在GUI程序的事件处理当中

有队列

还有操作系统的任务调度

磁盘的I/O等等,都涉及到队列

我们就不详细展开了。本章的内容,就到此结束,下一章

我们将进入数组,同学们,加油!

数据结构课程列表:

第0章 课程简介

-讲解

-作业

-讨论1

-讨论2

第1章 绪论

-1.1 数据结构是什么

--讲解

--作业

-1.2 概念和术语

--讲解

--作业1

--作业2

-1.3 抽象数据类型

--讲解(上)

--讲解(下)

--作业

-1.4 算法及其设计要求

--讲解

--作业

-1.5 算法分析与度量

--讲解(上)

--讲解(下)

--作业1

--作业2

--讨论

第2章 线性表

-2.1 概念及ADT

--讲解

--作业

-2.2 线性表的顺序实现——顺序表

--讲解(上)

--讲解(中)

--讲解(下)

--作业1

--作业2

-2.3 线性表的链式实现——链表

--讲解(上)

--讲解(中)

--讲解(下)

--作业1

--作业2

-2.4 线性表的应用——多项式

--讲解

--作业

-讨论

第3章 栈和队列

-3.1 栈的定义及ADT

--讲解

--作业

-3.2 栈的顺序实现——顺序栈

--讲解

--作业

-3.3 栈的应用

--讲解

--作业

-3.4 栈与递归

--讲解(上)

--讲解(下)

--作业

-3.5 队列的定义及ADT

--讲解

--作业

-3.6 队列的顺序实现——循环队列

--讲解(上)

--讲解(下)

--作业

-讨论

第4章 数组

-4.1 数组的定义

--讲解

--作业

-4.2 数组的顺序实现

--讲解

--作业1

--作业2

-4.3 特殊矩阵的压缩存储

--讲解

--作业

-4.4 稀疏矩阵的压缩存储

--讲解(上)

--讲解(下)

--作业

-讨论

第5章 树和二叉树

-5.1 概念及术语

--讲解

--作业

-5.2 二叉树及其性质

--讲解

--作业1

--作业2

-5.3 二叉树的存储

--讲解

--作业

-5.4 二叉树的遍历及创建

--讲解(上)

--讲解(下)

--作业

-5.5 线索二叉树

--讲解

--作业

-5.6 树与森林

--讲解

--作业

-5.7 Huffman树

--讲解(上)

--讲解(下)

--作业

-讨论

第6章 图

-6.1 概念和术语

--讲解

--作业

-6.2 存储与实现

--讲解(上)

--讲解(下)

--作业

-6.3 遍历

--讲解(上)

--讲解(下)

--作业

-6.4 最小生成树

--讲解(上)

--讲解(下)

--作业1

--作业2

-6.5 拓扑排序

--讲解

--作业

-6.6 最短路径

--讲解

--作业

-讨论

第7章 查找

-7.1 概念和术语

--讲解

--作业

-7.2 静态查找表

--讲解(上)

--讲解(下)

--作业

-7.3 二叉排序树

--讲解(上)

--讲解(下)

--作业

-7.4 平衡二叉树

--讲解

--作业

-7.5 哈希表

--讲解(上)

--讲解(下)

--作业

-讨论

第8章 排序

-8.1 概念

--讲解

--作业

-8.2 插入排序

--讲解(上)

--讲解(下)

--作业

-8.3 交换排序

--讲解(上)

--讲解(下)

--作业

-8.4 选择排序

--讲解(上)

--讲解(中)

--讲解(下)

--作业

-8.5 归并排序

--讲解

--作业

-讨论

讲解(下)笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。