队列
Last updated
队列(Queue)。队列简称队。是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。向队列中插入元素称为入队或进队;删除元素称为出队或离队。其操作特性为先进后出(First In Last Out,FIFO),并且只允许在队尾进,队头出。
队头(Front):允许删除的一端,又称队首
队尾(Rear):允许插入的一端
空队列:不包含任何元素的空表
1)InitQueue(&Q):初始化队列,构造一个空队列Q
2)QueueEmpty(Q):判断一个队列是否为空
3)EnQueue(&Q,x):入队,若队列未满,则将x加入使之成为新队尾
4)DeQueue(&Q,&x):出队,若队列非空,则将队首元素删除,并用x返回
5)GetHead(Q,&x):读队头元素,若栈顶元素非空,则用x返回栈顶元素
队列的顺序实现市值分配一块连续的存储单元存放队列中的元素,并附设两个指针 front 和 rear 分别指示队头元素和队尾元素的位置。设队头指针指向队头元素,队尾指针指向队尾元素的下一个位置。
队列的顺序存储类型可描述为:
初始状态(队空):Q.front == Q.rear == 0;
进队操作:队不满时,先送值到队尾元素,将队尾指针加1
出队操作:队非空时,先删除队头元素,再将队头指针加1
由上可知,Q.front == Q.rear == 0 可以作为队列的判空条件,但能否能用 Q.rear == MAXSIZE 作为队列已满的条件呢?显然是不行的,因为队尾指针可能已经到了最尾端,但是队头指针可能不在初始位置,而是在队列的中间,这时入队出现“上溢”,但这种溢出并不是真正的溢出,data数组中仍存在可以放置元素的位置,所以为“假溢出”。
前面指出了队列的缺点,这里就引出循环队列的概念。将队列臆造成一个环状的空间,即把存储队列元素的表从按逻辑上视为一个环,称为循环队列。当队首指针 Q.front == MAXSIZE - 1,再前景一个位置就自动到0,这可以利用除法取余运算(%) 来实现。
初始化时:Q.front = Q.rear = 0;
队首指针进1:Q.front = (Q.front + 1) % MAXSIZE;
队尾指针进1:Q.rear = (Q.rear + 1)% MAXSIZE;
队列长度:(Q.front + MAXSIZE - Q.rear) % MAXSIZE;
循环队列如何判断队满还是队空?
1)一般的做法是:入队时少入对一个队列单元,约定“队尾指针的下一个标志是队头指针 作为 队满的标志“:
队空条件:Q.front == Q.rear
队满条件:(Q.rear + 1) % MAXSIZE == Q.front
队列长度:(Q.rear - Q.front + MAXSIZE )% MAXSIZE
2)在类型中添加表示成员个数的数据成员。队空时 Q.size == 0;队满时 Q.size == MAXSIZE
3)类型中添加tag 数据成员,以区分是队满还是对空。tag ==0 ,若因删除导致Q.front == Q.rear ,则为队空;若tag == 1,若因添加导致Q.front == Q.rear,则为队满。
1、初始化
2、判队空
3、入队
4、出队
队列的链式存储又称为 链队列,它实际上是一个同时带有一个队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向最后一个结点。
不带头结点的链式队列
队列的链式存储类型可描述为:
当Q.front == nullptr 且 Q.rear == nullptr 时,链式队列为空。
出队时,若不空,则将队头元素删除,Q.front 指向下一个结点;入队时,新建一个结点,将新结点插入到链队列的尾端,并让Q.rear指向这个新插入的结点。
不带头结点的链式队列在操作上往往比较麻烦,因此通常将链式队列设计成一个带头结点的单链表,这样插入和删除就统一了。
1、初始化
2、判队空
3、入队
4、出队
双端是允许两端都可以进行入队和出队操作的队列。逻辑结构仍然是线性结构,将队列的两端分别称为前端和后端,连段都可以入队和出队。
在双端队列进队时,前端进的元素排列在队列中后端进的元素的前面,后端进的元素排在前端进的元素的后面。在双端队列中,无论是前端还是后段,先出去的元素排列在后出去的元素前面。
输出受限的双端队列:有一端不能进行删除,这样的双端队列叫做 输出受限的双端队列。
输入受限的双端队列:有一端不能进行插入,这样的双端队列叫做 输出受限的双端队列。