队列是另一种限定性的线性表,它只允许在表的一端插入元素,而在另一端删除元素,所以队列具有先进先出(FIFO)/后进后出的特性。
在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front)。
与线性表类似,队列也可以有两种存储表示,即顺序表示和链式表示。
队列之顺序队列
循环队列是队列的一种顺序表示和实现方法。
与顺序栈类似,在队列的顺序存储结构中,可以用一组地址连续的存储单元依次存放从队头到队尾的元素,如一维数组array[MAXSIZE]。此外,由于队列中队头和队尾的位置都是动态变化的,因此需要附设两个指针front和rear,分别指示队头元素和队尾元素在数组中的位置。
初始化队列时,令front=rear=0;入队时,直接将新元素送入尾指针rear所指单元,然后尾指针增1;出队时,直接取出队头指针front所指的元素,然后头指针增1。
显然,在非空顺序队列中,队头指针始终指向当前的队头元素,而队尾指针始终指向真正队尾元素后面的单元。
当rear= =MAXSIAE时,认为队满。但此时不一定是真的队满,因为随着部分元素的出队,数组前面会出现一些空单元。由于只能在队尾入队,使得上述单元无法使用。我们把这种现象称为假溢出,真正队满的条件是rear–front= =MAXSIZE。
假溢出:顺序队列因多次入队和出队操作后出现的尚有存储空间但不能再进行入队操作的溢出。
真溢出:顺序队列最大存储空间已经存满而又要求进行入队操作所引起的溢出。
为了解决假溢出现象并使得队列空间得到充分利用,一个较巧妙的办法是将顺序队列的数组看成一个环状的空间,即规定最后一个单元的后继为第一个单元,我们形象地称之为循环队列。
(1)假设队列数组为array[MAXSIZE],当rear+1= =MAXSIZE时,令rear=0,即可求得最后一个单元array[MAXSIZE-1]的后继:array[0]。
(2)更简便的办法是通过数学中的取模(求余)运算来实现:rear=(rear+1)mod MAXSIZE。显然,当rear+1=MAXSIAE时,rear=0,同样可求得最后一个单元array[MAXSIZE-1]的后继:array[0]。
所以,借助取模(求余)运算,可以自动实现队尾指针、队头指针的循环变化。
进队操作时,队尾指针的变化是:rear=(rear+1)mod MAXSIZE;而出队操作时,队头指针的变化是:front=(front+1)mod MAXSIZE。
与一般的非空顺序队列相同,在非空循环队列中,队头指针始终指向当前的队头元素,而队尾指针始终指向真正队尾元素后面的单元。
可见,只凭front= =rear无法判别队列的状态是“空”还是“满”。对于这个问题,可有两种处理方法:一种方法是少用一个元素空间。当队尾指针所指向的空单元的后继单元是队头元素所在的单元时,则停止入队。这样一来,队尾指针永远追不上队头指针,所以队满时不会有front= =rear。现在队列“满”的条件为(rear+1)mod MAXSIZE= =front,判队空的条件不变,仍为rear= =front。另一种是增设一个标志量,以区别队列是“空”还是“满”。预设一个标志位flag,初值=0,每当入队成功,flag=1;每当出队成功,flag=0;那么,front= =rear && flag可区别队列“空”和“满”两种状态。还有一种方法是使用一个计数器记录队列中元素的总数(实际上是队列长度)【最简单方便的方法】
顺序队列定义如下
typedef int DataType;
#define MAXSIZE (10)
typedef struct SeqQueue
{
DataType array[Queue_Size];//循环队列占用的数组空间
int front;//头指针指示器
int rear;//尾指针指示器
} SeqQueue;
队列之链队列
用链表表示的队列简称为链队列。
为了操作方便起见,这里采用带头结点的链表结构,并设置一个队头指针和一个队尾指针。队头指针始终指向头结点,队尾指针指向当前最后一个元素。空的链队列的队头指针和队尾指针均指向头结点。
通常将队头指针和队尾指针封装在一个结构体中,并将该结构体类型重命名为链队列类型。
链队列定义如下
typedef int DataType;
typedef struct LinkQueueNode
{
DataType data;
struct node *next;
} LinkQueueNode;
typedef struct LinkQueue
{
LinkQueueNode *front;
LinkQueueNode *rear;
} LinkQueue;
相关代码
链队列
队列之优先级队列
带有优先级的队列称为优先级队列。
队列具有先进先出的特性,即最先进入队列的元素将被最先出列。有时也需要把进入队列中的元素分优先级(比如线程调度),出队时首先选择最高的元素出队列(优先级高先被服务,VIP),对于优先级相同的元素则按先进先出的原则出队列。即优先级队列的出队操作不是直接将队头元素出队列,而是把队列中优先级最高的元素出队列。
实现优先级队列往往不用队列这个结构,单纯用队列这个结构是比较复杂的。
2、通过堆来实现
队列的应用
生产者消费者模型(典型)
消息队列
排队现象
网络数据传输
队列的应用举例(教材)
1、打印杨辉三角
2、键盘输入循环缓冲区问题