一、队列的定义

队列(queue):队列是只允许在-端进行插入操作,而在另-端进行删除操作的线性表。队列是一种先进先出 (First In First Out) 的线性表,简称 FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

数据结构的基本任务(数据结构队列)(1)

队列

队列(Queue)与栈一样,是一种线性存储结构,它具有如下特点:

线性表有顺序存储链式存储,栈是线性表,所以有这两种存储方式。队列作为一种特殊的线性表,也同样存在着这两种存储方式。

二、队列的顺序存储

我们假设一个队列有 n 个元素,则顺序存储的队列需建立一个大于 n 的数组,并把队列的所有元素存储在数组的前 n 个单元,数组下标为0的一端即是队头。

数据结构的基本任务(数据结构队列)(2)

队列的顺序存储

顺序存储的入队操作:

所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为O(1)。

数据结构的基本任务(数据结构队列)(3)

顺序存储的入队操作

顺序存储的出队操作:

队列与栈不同的是,队列元素的出队是在队头,即下标为0的位置,所以队列中的所有元素都得向前移动,以保证队列的队头,也就是下标为0的位置不为空,此时时间复杂度为O(n)

数据结构的基本任务(数据结构队列)(4)

顺序存储的出队操作

我们发现队列的顺序存储与现实情况非常相似,大家排队做核酸,先来的人先去做,当第一个人做完核酸离队后,其他人都向前进一位。我们可以发现,现在我们是限制了元素必须存储在顺序表的前 n 个元素,如果我们不限制元素在顺序表的位置,该如何做呢。

三、首尾指针的顺序存储

front 指针指向队头元素 , rear 指针指向队尾元素的下一个位置。假设数组的长度为 5,初始状态,空队列时 front 与 rear指针均指向下标为0的位置;

数据结构的基本任务(数据结构队列)(5)

空队列

然后入队a1、 a2、 a3、a4,front指针依然指向下标为0位置,而rear指针指向下标为4的位置。

数据结构的基本任务(数据结构队列)(6)

入队

出队 a1、a2 ,则front指针指向下标为2的位置, rear 不变。

数据结构的基本任务(数据结构队列)(7)

出队

再入队 a5,此时数组已经溢出了,但是下标为0,1的位置实际上是空闲的。

数据结构的基本任务(数据结构队列)(8)

假溢出

由上图我们发现,队列的大小是5,但实际上我们只有3个元素,由于 rear 指针已经在数组尾部,再进行入队就发生了数组的越界,这就是顺序队列的“假溢出”现象。

四、循环队列

解决假溢出的办法就是后面满了,就从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。

数据结构的基本任务(数据结构队列)(9)

循环队列

我们接着处理上面入队 a5元素的操作,如果是循环队列,我们可以把 rear 指针指向下标0的位置。

数据结构的基本任务(数据结构队列)(10)

循环队列

接着入队a6,将它放置于下标为0处, rear 指针指向下标为1处。

数据结构的基本任务(数据结构队列)(11)

入队

接着入队a7,将它放置于下标为1的位置, rear 指针指向下标为2处。

数据结构的基本任务(数据结构队列)(12)

入队

此时我们发现 rear 与 front 相等,队列却满了,这不就与空队列为空的判断条件冲突了吗;在实际开发中,我们会预留一个空位置,就是数组只有一个空位置时,我们就认为队列满了。

数据结构的基本任务(数据结构队列)(13)

队满

由于 rear 可能比 front大,也可能比 front小,所以尽管它们只相差一个位置时就是队满的情况,但也可能是相差整整一圈。 我们假设队列的大小为QueueSize。

五、队列的链式存储结构

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已, 我们把它简称为链队列 。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点。

数据结构的基本任务(数据结构队列)(14)

队列的链式存储结构

空队列时, front和 rear都指向头结点。

数据结构的基本任务(数据结构队列)(15)

空队列

数据结构:

class Node<T>{ //数据 T data; //下一个元素指针 Node next; } class Queue{ //头指针 Node front; //尾指针 Node rear; }

六、队列的应用

1、键盘的输入与输出,比如你微信聊天输入god,由于队列是先进先出所以出来就是 god,如果是栈就是 dog。

2、打印机的任务

3、编程语言中线程池的任务队列

4、现在很多的消息中间件MQ

5、图的遍历

,