文章目录
队列
队列和栈一样,都是一种对数据的“插入”和“删除”有特殊要求的线性表
队列是什么
- 什么是队列?
只能在表的一端进行插入,另一端进行进行删除,且操作具有先进先出的原则的线性表成为队列。
- 什么是队头、队尾?
数据只能在队列的一端插入,另一端删除,所以:- 队列中进行删除的一端称为队头。
- 队列中进行插入的一端称为队尾。
若用 表示队列,则:
- 称为队头元素;
- 称为队尾元素;
- 没有元素的队列称为空队列。
-
什么是入队、出队?
因为队列操作的特殊性,队列常见的两种操作:- 插入数据到队尾的操作称为入队。
- 从队头删除第一个元素的操作称为出队。
-
队列的先进先出原则
- 先入队的元素在队头,最后入队的元素在队尾。
- 删除元素时最先入队的元素先出队,最后入队的元素最后出队。
-
什么是双端队列?
限定插入和删除操作在表的两端进行的线性表称为双端队列。
- 双端队列的演变
- 输出受限的双端队列,一个端点只允许插入和删除,另一个端点只允许插入。
- 输入受限的双端队列,一个端点只允许插入和删除,另一个端点只允许删除。
- 双端队列也可以退化成栈,即只能在一端进行插入和删除。
队列基本操作
- 向队尾添加元素(入队)
- 删除队首元素(出队)
- 获取队首的元素值(存取)
- 判断队列是否为满
- 判断队列是否为空
顺序队列
- 什么是顺序队列?
用顺序存储方式存储的队列称为顺序队列。
- 元素出队时队头元素如何处理?
元素入队只要将元素添加到队列的最后一个位置即可,但元素出队时在顺序队列中队头元素的位置是否变化,分两种情况讨论:- 元素出队后,新的队头元素不要求必须放在存储空间的第一个位置。元素出队后,只需将下一个元素设置成新的队头即可。
- 优点:不会改变队列中其他元素地址;
- 缺点:随着元素的出队,队列的队头的存储位置后移,可能出现存储空间不足,新元素无法入队,而队头前端大量存储空间被闲置,造成空间的浪费。
- 元素出队后,新队的队头元素必须存放在存储空间的第一个位置。元素出队后,所有元素向前移动一个位置。
- 优点:有效的利用了存储空间;
- 缺点:所有元素存储位置都要改变,时间效率低。
- 元素出队后,新的队头元素不要求必须放在存储空间的第一个位置。元素出队后,只需将下一个元素设置成新的队头即可。
出于对空间和时间效率的考虑,暂时牺牲空间换取时间,通常队列操作采用方式 1。
- 队列指针的设置及队空判断
根据队列出队和入队的特点,队列设置两个指针分别指向队头和队尾:- 设 指针为队头指针,指示队头元素在顺序队列中的位置
- 设 指针为队尾指针,指示队尾元素的下一个位置,初始值指向队头:
- 用 表示队列的存储空间大小
- 当 时队空,当 时队列溢出,不能再添加元素
顺序队列的初始化
- 为顺序队列分配初始存储空间 ,使 指向空间的基地址。
- 设 。
顺序队列的入队
- 判断队列是否溢出,若溢出不能再添加元素
- 否则将新元素入队,队尾指针加 1:
顺序队列之出队
- 判断队列是否为空,若队空则不能删除元素
- 否则队头元素出队,队头指针加 1:
循环队列
为了解决顺序队列元素出队时造成的存储空间浪费,可以假定顺序队列是一个封闭的环,提升运算效率与空间效率之间的矛盾
- 什么是循环队列?
将队头与队尾连接形成闭环的队列城为循环队列。
-
队列指针
循环队列与顺序队列一样,设置队头指针 和队尾指针 :- 元素出队, 顺时针移动一个位置;
- 元素入队, 顺时针移动一个位置。
-
队满的争议?
与顺序队列的溢出不同,循环队列队满时便不能再添加新的元素,若 和 指针的定义与顺序队列中相同,则出现 时无法判断队列是满还是空的情况,所以如何判断队满?- 新增变量 标识队列元素个数,当 时为队满;当 时队空。
- 循环队列少用一个元素,当队头指针在队尾指针的下一个位置时,队列为满,队列元素为 ;当 时队空。
为了操作的便捷性,通常采用方式 2 判断队空队满,以下循环队列的操作以方式 2 为基准。
- 如何判断队空队满?
循环队列的 和 指针的定义与顺序队列中相同,队空队满及队列元素个数判断如下:- 当 时队满;
- 当 时队空;
- 队列中有效元素个数:。
循环队列的初始化
- 为循环队列分配初始存储空间 ,使 指向空间的基地址。
- 设 。
循环队列有效长度
- 循环队列的有效长度:
循环队列的入队
- 判断循环队列是否为满: ,若队满则不能添加新元素
- 否则将新元素入队,队尾指针加 1:
循环队列之出队
- 判断队列是否为空:,若队空则不能再删除元素
- 否则队头元素出队,队头指针加 1:
链式队列
- 什么是链式队列?
用链接存储方式实现的队列称为链式队列。
- 链式队列的指针
链式队列添加头结点,使头指针指向头结点,同时增设两个指针:- 设队头指针 ,始终指向头结点
- 设队尾指针 ,指向队尾结点,初始化时 指向头结点
链式队列的初始化
操作步骤如下:
- 创建一个新结点作为链式队列的头结点,并将队头和队尾指针指向头结点
- 头结点的指针域为
链式队列的入队
链式队列的入队就是将数据元素插入到队尾,具体操作如下:
- 创建指针域为 的新结点
- 将新结点插入到队尾结点之后,修改队尾结点指针域:
- 修改队尾指针:
链式队列之出队
链式队列的出队就是删除链表的首元结点,具体操作如下:
- 判断队列是否为空,若为空则不能删除结点
- 否则获取首元结点 的数据域
- 进行删除首元结点操作,修改队头指针指向下一个结点:
- 元素出队后再次判断队列是否为空,若为空将队尾指针指向头结点:
- 释放结点
循环队列和链式队列的比较
-
时间复杂度
- 循环队列和链式队列入队和出队的时间复杂度都为
-
空间上复杂度
- 循环队列初始化时必须申请存储空间,队列的有效长度受限,在操作过程中队列的有效元素个数小于存储空间大小,所以造成空间浪费。
- 链式队列存储过程中需要一个指针域,会产生空间上的开销,但队列元素个数不会受限制。
顺序队列与链式队列的比较
- 顺序队列有固定的存储空间,不适用于存储空间很大,删除插入很频繁的操作,此时顺序队列的空间利用率很低;反之,链式队列适用此情况。
- 顺序队列的访问简单,对队列内部元素的访问便捷;链式队列元素需便利整个链表。
应用实例
- 银行拿号排队问题
参考资料:
[1] 《数据结构(C语言版)》 严魏敏、吴伟民著
[2] 《数据结构(第3版)》 刘大有等著