队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性表
文章目录
- 前言
- 一.队列的定义
- 二.队列的数据类型
- 三,循环队列
- 四.队列的链式存储结构
前言
栈是限定仅在表尾进行插入和删除操作的线性表。
队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性表。
提示:以下是本篇文章正文内容,下面案例可供参考
一.队列的定义
你们在用电脑时有没有经历过,机器有时会处于疑似死机的状态,鼠标点什么似乎都没用,双击任何快捷方式都不动弹。就当你失去耐心,打算 reset 时。突然它像酒醒了一样,把你刚才点击的所有操作全部都按顺序执行了一遍。这其实是因为操作系统中的多个程序因需要通过一个通道输出,而按先后次序排队等待造成的。
再比如像移动、联通、电信等客服电话,客服人员与客户相比总是少数,在所有的客服人员都占线的情况下,客户会被要求等待,直到有某个客服人员空下来,才能让最先等待的客户接通电话。这里也是将所有当前拨打客服电话的客户进行了排队处理。
操作系统和客服系统中,都是应用了一种数据结构来实现刚才提到的先进先出的排队功能,这就是队列。
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。假设队列是q=( a1,az,……,an),那么a1就是队头元素,而an是队尾元素。这样我们就可以删除时,总是从a1开始,而插入时,列在最后。这也比较符合我们通常生活中的习惯,排在第一个的优先出列,最后来的当然排在队伍最后。
二.队列的数据类型
同样是线性表,队列也有类似线性表的各种操作,不同的就是插入数据只能在尾进行,删除数据只能在队头进行。
ADT 队列(Queue)
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
InitQueue(*Q):初始化操作,建立一个空队列Q。
DestroyQueue(*Q):若队列Q存在,则销毁它。
ClearQueue(*Q):将队列Q清空。
QueueEmpty(Q):若队列Q为空,返回true,否则返回false。
GetHead(Q,*e):若队列Q存在且非空,用e返回队列Q的队头元素。
EnQueue(*Q,e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素。
DeQueue(*Q,*e):删除队列Q中队头元素,并用e返回其值。
QueueLength(Q):返回队列Q的元素个数
endADT
三.循环队列
线性表有顺序存储和链式存储,栈是线性表,所以有这两种存储方式。同样,队列作为一种特殊的线性表,也同样存在这两种存储方式。我们先来看队列的顺序存储结构。
循环队列的顺序存储结构代码如下:
typedef int QElemType;/* QElemType 类型根据实际情况而定,这里假设为int *// * 循环队列的顺序存储结构 */
typedef struct
QElemType data[MAXSIZE];
int front; /* 头指针 */
int rear; /*尾指针,若队列不空,指向队列尾元素的下一个位置*/
SqQueue;
循环队列的初始化代码如下:
/* 初始化一个空队列Q */
Status InitQueue (SqQueue *Q)
Q->front=0;
Q->rear=0;
returnOK;
循环队列求队列长度代码如下:
/* 返回Q的元素个数,也就是队列的当前长度*/
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)MAXSIZE;
}
循环队列的入队列操作代码如下:
/* 若队列未满,则插入元素e为Q新的队尾元素*/
Status EnQueue(SqQueue *Q, QElemType e)
if ((Q->rear+1)MAXSIZE ==Q->front)/*队列满的判断*/
return ERROR;
Q->data[Q->rear]=e; /* 将元素e赋值给队尾 */
Q->rear=(Q->rear+1)MAXSIZE; /*rear指针向后移一位置,*/
/*若到最后则转到数组头部 */
return OK;
循环队列的出队列操作代码如下:
从这一段讲解,大家应该发现,单是顺序存储,若不是循环队列,算法的时间性能是不高的,但循环队列又面临着数组可能会溢出的问题,所以我们还需要研究一下不需要担心队列长度的链式存储结构。
四.队列的链式存储结构
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点。
空队列时,front和rear都指向头结点。
链队列的结构为:
typedef int QElemType; /* QElemType 类型根据实际情况而定,这里假设为int */typedef struct QNode /*结点结构*/
QElemType data;
struct QNode*next;
QNode, *QueuePtr;
typedef struct /*队列的链表结构 */
QueuePtr front, rear;/*队头、队尾指针 */
LinkQueue;
总结
到了总结回顾的时间。我们的是栈和队列,它们都是特殊的线性表,只不过对插入和删除操作做了限制。
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性
它们均可以用线性表的顺序存储结构来实现,但都存在着顺序存储的一些弊端。
因此它们各自有各自的技巧来解决这个问题。
对于栈来说,如果是两个相同数据类型的栈,则可以用数组的两端作栈底的方法来让两个栈共享数据,这就可以最大化地利用数组的空间。
对于队列来说,为了避免数组插入和删除时需要移动数据,于是就引入了循环队列,使得队头和队尾可以在数组中循环变化。解决了移动数据的时间损耗,使得本来插入和删除是0(n)的时间复杂度变成了0(1)。
它们也都可以通过链式存储结构来实现,实现原则上与线性表基本相同。