在本次博客当中我们来学习一下队列的构建。首先来介绍一下队列。队列也是一种被限制的线性表。队列要求我们其中的元素只可以从队尾进入从队头出数据。也就是说我们先进入队列的数据就会先出队列。所以我们可以将我们的两种线性表改编成为我们的队列。话题又回到了我们两种线性表我们应该选择哪一种呢?
假如我们依旧使用顺序表的话,我们每次从队尾插入数据,这一步操作很简单,但是我们删除数据呢?需要从队头进行数据的删除。按照我们顺序表的构建我们需要将后面的数据依次向前移动覆盖前面的数据以达到数据覆盖的效果。这样就会造成我们时间上的损耗。所以我们对于队列的构建就采用链表的形式。假如需要插入数据我们就采用尾插的函数,假如我们想要删除数据就采用头删的函数。
那么问题又来了:我们需要采用双向链表还是单链表呢?我们来分析一下:对于我们的队列我们需要在队尾插入元素,在我们链表的构建当中我们只能通过遍历才可以找到链表的最后一个元素,从这一点来看使用双循环链表似乎更具有优势。但是我们再来分析一下我们的队列,队列当中其他功能的完善似乎并不需要用到循环链表当中的功能,所以我们可以考虑能不能将我们单链表进行完善一下,直接使用单链表实现我们的队列。
方法肯定是有的,我们只需要在我们链表当中增加一个尾节点即可。也就是构建如下的结构体:
在这一个结构体当中我们需要做到的是统帅大局,也就是将我们这个结构体看成一个完整的队列,在这个结构体当中保存着队列的头节点,尾节点,以及节点的个数。
但是按照我们正常的链表的构建我们还需要构建一个一个的小的节点,并使用next指针将我们这些节点串联起来,所以我们就又需要构建一个结构体:
接着我们就可以按照我们正常的链表的编写逻辑进行队列的构建了。同样的我们先将我们在队列当中需要实现的函数按照思维导图的形式展示出来:
🌵初始化队列
对于我们队列的初始化就是将我们宏观上调控队列的结构体进行初始化操作,也就是将我们的head和tail置空,再将size归零即可。所示代码如下:
🌵 向队列当中插入数据
只要是需要增添数据的函数我们首先要考虑的都是是否需要扩容或者是开辟新的数据空间。所以我们需要先实现一个用于开辟新的节点的函数:
之后我们将我们开辟好的新节点链接给我们的队列即可。(实质上就是独自构建一个链表将我们构建好的链表的头节点和尾节点赋值给我们队列的结构体即可。)在如数据的时候我们需要考虑如何将我们的每一个节点连接起来。我们依旧使用next指针进行连接,但是沃尔玛呢需要先判断情况,如果我们队列当中没有数据也就是size为0,那么我们就需要将我们的头节点和尾节点都更改为我们新开辟的节点。如果我们的队列当中已经存在数据,那么我们只需要更改我们的尾节点的地址即可。在完成一切操作之后再进行 size++ 让我们队列保存的数据和实质上的个数一致。所示的代码如下:
通过调试所检测我们上述代码的运行效果:
我们会发现我们依次插入的1,2,3,4一切正常。我们可以进行其他函数的编写。
🌵 从队头拿出数据
从队列当中拿出数据换句话来说就是从我们的队列当中删除一个元素。当我们需要进行数据的删除的时候我们需要先判断一下我们队列当中是否存在数据。如果不存在数据就不允许再进行数据的删除。之后将我们队列当中的头指针指向我们的next指针即可。所示的代码如下:
我们将头节点更改完毕之后将我们原本的头节点释放,并将我们的size--即可。通过调试进行检测情况如下:
我们通过调试会发现我们原本队列当中的1也就是我们头节点当中的元素已经被我们删除了。代码运行一切正常。继续编写其它部分的代码。
🌵 判断队列的大小
对于判断队列的大小,这个函数超级简单。还记得我们之前在队列当中增加的size变量吗?有了这个变量我们在编写这个函数就不需要在进行遍历链表了。我们只需要将我们的size作为返回值返回即可,代码如下:
我们可以在主函数当中调用这个函数进行检测我们这项功能是否正常:
我们先向队列当中插入四个数据之后再删除一个数据所以我们队列当中剩下三个数据我们调用函数所输出的数据的个数也为3,所以我们这部分的函数运行一切正常。
🌵 队列的判空
对于队列的判空我们只需要对size进行判断是否等于0即可,如果为0就代表我们的队列为空,就返回true,否则就返回false。所示代码如下:
同样的我们可以对我们的函数进行检测:
如上图所示,我们对于队列的判空操作无论是队列为空还是队列不为空的检测都正常。
🌵 返回队头元素
返回队头元素的函数同样十分的简单。我们只需要返回我们头节点所指向的节点当中所存储的元素即可。所示代码如下:
对我们上述的函数进行检测:
我们的队头元素也确实为1,所以函数运行正常。
🌵 返回队尾元素
返回队尾元素我们只需要直接返回我们的队尾节点所指向的元素即可。所示的代码如下:
上述代码的运行效果如下:
函数功能正常。
🌵 销毁队列
最后我们需要实现的就是我们的销毁队列的函数了。对于队列的销毁函数和我们链表的销毁函数相同。我们只需要先创建一个节点变量接受我们原先的头节点之后再将我们的头节点指向我们的next指针指向的地址即可。之后再将我们使用变量保存好的原先头节点的地址释放。最后依次循环进行此操作,一直到所有的节点均释放。我们这一部分所示的代码如下:
在完成上述所有的函数之后我们队列的构建也就全部完成了。相对于我们链表的构建来说队列的创建就显得简单很多了,大家会发现我们的栈和队列看起来有很大的不同,要是让大家使用栈构建一个队列或者使用队列构建一个栈呢?我们将在下一次的博客当中实现这两种数据结构之间的相互转换。感谢您的观看,再见。