数据结构--队列--顺序循环队列的操作实现(C语言)

文章目录

  • 队列是个什么样的数据结构?
  • 循环队列
  • 顺序循环队列的实现
    • ⭐1.创建初始化队列
    • ⭐2.入队
    • ⭐3.出队
    • ⭐4.队列遍历打印
    • ⭐5.清空队列
    • ⭐6.判断队列空
    • ⭐7.判断队列满
    • ⭐8.动态内存释放
  • 总结


本文中涉及的完整代码及各操作测试代码均已提交至Gitee,大家可以点击链接参考。
鄙人乃是一介初学者,文中及代码中难免出错,请同志们批评指正!
在这里插入图片描述


队列是个什么样的数据结构?

我们前面介绍过栈,栈乃是一个只有一个口的直筒子。那么队列,其实是一个两端开口的直筒子。
其实这里的队列就基本相当于我们生活中的队列。举例一个场景:我们最近经常要做核酸排长队,队伍从队头做完核酸退出队列,新来的人从队尾加入队列。这也是数据结构中队列的数据插入、删除的操作。我们来给队列下一个定义:

队列( queue )是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一-端称为队尾,允许删除的一端称为队头。假设队列是q= ( a1, a2, … an),那么a1就是队头元素,而an是队尾元素。这样我们就可以删除时,总是从a1开始,而插入时,列在最后。这也比较符合我们通常生活中的习惯,排在第一一个的优先出列, 最后来的当然排在队伍最后。
数据结构--队列--顺序循环队列的操作实现(C语言)_第1张图片

循环队列

在介绍循环队列之前,我们先来考虑最普通最容易想到的队列的实现流程。
1.入队:
我们假定有一个数组,这个数组可以放5个元素,其下标从0到4,其中下标为0的地方我们称之为队头。如果要往里面放入元素,就从队尾开始追加。队尾的位置是当前最后一个元素所在位置。如下图。
数据结构--队列--顺序循环队列的操作实现(C语言)_第2张图片
2.出队:
如果要出队列,因为只允许从队头开始删除元素,所以下标为0的元素被删除。为了能让队头不空,后面的元素需要向前移动,这和顺序表的表头删除操作一模一样,其时间复杂度为O(n)。
数据结构--队列--顺序循环队列的操作实现(C语言)_第3张图片
3.改善
上面操作因为需要把元素整体移动,如果元素较多,这种移动无疑会耗费大量的时间,影响性能。那能不能不移动元素,而是移动队头呢?当下表为0的元素删除后,队头从下标为0的位置移动到下标为1的位置。这样使得队列的性能大大提高。因为其时间复杂度变为O(1)了。
数据结构--队列--顺序循环队列的操作实现(C语言)_第4张图片
4.问题
为了表示队头、队尾的位置,我们在程序中设定两个变量:front、rear。规定front指向队头元素的位置;rear指向队尾元素的下一个位置。
数据结构--队列--顺序循环队列的操作实现(C语言)_第5张图片
如上图中左图,当队列为空时,front和rear指向同一个位置,那么在编程时,当front==rear时,我们可以判定队列为空队列。向空队列中继续放入元素,直到rear指向数组最后一个空位。
此时我们进行出队操作,但是只移动队头,即front的位置,当我们删除两个元素后,front指向了下标为2的位置,如下图左图:
数据结构--队列--顺序循环队列的操作实现(C语言)_第6张图片
但是,如果我们继续向队列中放入元素,那么依旧是从队尾进行插入,然而,当我们放入一个元素后,队尾指针rear竟然指向了数组之外,这就造成了数组越界的问题。可能你会想,既然如此,我们就规定rear的位置指向下标为4的位置的时候判定队列为满,不允许继续插入就好了。但是,rear指针告诉我们队列已满,实际上我们队列的前面两个地方还空着呢,队列并没有满,这不是造成了很大的空间浪费吗?实际上,这种情况被称为“假溢出”。那么为了解决这样的问题,需要同时考虑到时间复杂度和数组越界,该如何解决呢?

5.问题的解决:循环队列
那么解决上面的问题,我们可以这样想:既然后面满了,而前面还空着,为什么不让新增的元素从头开始存储呢?这样,整个本来是直筒子的队列形成了一个头尾相接的圆环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。

数据结构--队列--顺序循环队列的操作实现(C语言)_第7张图片
入上图,当想要放入a5 元素时,我们将其放入到队列中的最后一个空位中,但是队尾指针指向了最最开始的队头,也就是下标为0的位置。这样数组访问有址可循,不会出现数组越界访问的问题。接下来,我们

你可能感兴趣的:(数据结构入门,数据结构,c语言)