个人主页:李仙桎
🔥 个人专栏: 《数据结构与算法》
⛺️生活的理想,就是为了理想的生活!
⛺️前言:各位铁汁们好啊!!!,今天继续学习数据结构相关的内容,后续不断更新数据结构有关知识内容!!希望各位铁汁多多支持!这一章节主要是《数据结构》第三章 栈和队列 队列的相关知识总结。
队列的介绍
队列(Queue)就像是食堂排队打饭的人群。想象一下你去食堂打饭,人们在打饭窗口形成一条线(队列)等待打饭。队列遵循一个很重要的原则:先进先出(First In, First Out,简称FIFO)。这意味着最先到达并排队的人将会是第一个打饭并离开队列的人,随后到达的人则依次排在队伍的后面,等待打饭。
队列是只允许在一端进行插入操作(入队),而在另一端进行删除操作(出队)的线性表
队列的存储结构
线性表有两种存储结构:顺序存储和链式存储,在栈中我们知道,栈存在两种存储结构,队列作为特殊的线性表,也同样存在这两种存储结构
队列的顺序存储结构
队列的顺序存储结构,就是线性表的顺序表,只不过它只能尾进头出,我们在静态数组来存放元素,队头指针和队尾指针分别指向队头和队尾
初始化操作
入队操作
注意为什么队尾值需要取模运算,因为我们出队(删除表头元素)操作时候,我们静态数组的data[0]、data[1]...data[front]位置就会空,这可能会造成队头不在数组的起始位置。 插入队列时候如果rear只是简单+1,那我们当继续向队列中添加元素而队尾已经达到数组的最末端时,若不采取任何措施,就无法再添加新的元素,即使数组的前部(队头之前的部分)是空闲的 。这种情况看起来好像数组已经"溢出"了,但实际上是因为未充分利用数组的空间,称为"假溢出 "。解决假溢出的办法就是后面满了,再从头开始,头尾相接的循环,把队列这种头尾相接的顺序结构称为循环队列,(rear+1)%MaxSize
难么怎么判断队列是空的还是满的?
我们让队列判空条件还是front=rear,
此时队列是满的,但是front等于rear,这个条件有有可能对应队列是空的,那么我们该怎样判断队列是满的还是空的?
解决办法:
①我们让队列判空条件还是front=rear,当队列满时,我们修改条件,使其保留一个元素空间,也就是队列满时,还有一个空闲单元。rear可能比front大,也可能比front小,相差一个位置即为满
则队列满的条件是**(rear+1)%MaxSize==front,队列的元素个数:(rear+MaxSize-front)%MaxSize**
这种顺序存储若不是循环队列,算法性能不高,循环队列又面临着数组溢出的问题,我们接下来讲解队列的链式存储结构
②此外我们还可以再定义队列的时候加入一个int变量来记录当前队列的长度,插入成功size++。 删除成功size--。那么我们可以用size判断队列空还是满,此时不需要我们牺牲一个元素空间
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;
int size;
} SqQueue;
③此外我们还可以再定义队列的时候加入一个int变量来记录最近进行的是插入还是删除
出队操作
队列的链式存储结构
链队列的构建
这里的队列是通过链表实现的,链式存储方式的好处在于它可以动态地分配内存,避免了顺序队列中可能发生的假溢出问题,同时也不需要在队列初始化时就确定其最大容量。
front指针指向队列的头部(第一个元素),而rear指针指向队列的尾部(最后一个元素)。这两个指针是实现队列基本操作(如入队和出队)的关键
此外可以在定义队列的时候加入一个int型的变量size存储队列中当前的元素数量。这个信息对于快速获取队列的大小,以及确定队列是否为空等操作非常有用。