画解数据结构:队列
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了画解数据结构:队列相关的知识,希望对你有一定的参考价值。
零、前言
「 数据结构 」 和 「 算法 」 是密不可分的,两者往往是「 相辅相成 」的存在,所以,在学习 「 数据结构 」 的过程中,不免会遇到各种「 算法 」。
到底是先学 数据结构 ,还是先学 算法,我认为不必纠结这个问题,一定是一起学的。
数据结构 常用的操作一般为:「 增 」「 删 」「 改 」「 查 」。基本上所有的数据结构都是围绕这几个操作进行展开的。
那么这篇文章,作者将用 「 九张动图 」 来阐述一种 「 先进先出 」 的数据结构
「 队列 」
🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
闭关刷 LeetCode,剑指大厂Offer! 🌌《LeetCode 刷题指引》🌌
LeetCode 太简单?算法学起来! 💜《夜深人静写算法》💜
队列可以用 顺序表 实现,也可以用 链表 实现,浓缩为以下三张图:队列操作三部曲
队列的链表实现
队列的顺序表实现
看不懂没有关系,我会把它拆开来一个一个讲,首先来看一下今天要学习的内容目录。
文章目录
一、概念
1、队列的定义
队列 是仅限在 一端 进行 插入,另一端 进行 删除 的 线性表。
队列 又被称为 先进先出 (First In First Out) 的线性表,简称 FIFO 。
2、队首
允许进行元素删除的一端称为 队首。如下图所示:
3、队尾
允许进行元素插入的一端称为 队尾。如下图所示:
二、接口
1、可写接口
1)数据入队
队列的插入操作,叫做 入队。它是将 数据元素 从 队尾 进行插入的过程,如图所示,表示的是 插入 两个数据(绿色 和 蓝色)的过程:
2)数据出队
队列的删除操作,叫做 出队。它是将 队首 元素进行删除的过程,如图所示,表示的是 依次 删除 两个数据(红色 和 橙色)的过程:
3)清空队列
队列的清空操作,就是一直 出队,直到队列为空的过程,当 队首 和 队尾 重合时,就代表队尾为空了,如图所示:
2、只读接口
1)获取队首数据
对于一个队列来说只能获取 队首 数据,一般不支持获取 其它数据。
2)获取队列元素个数
队列元素个数一般用一个额外变量存储,入队 时加一,出队 时减一。这样获取队列元素的时候就不需要遍历整个队列。通过 O ( 1 ) O(1) O(1) 的时间复杂度获取队列元素个数。
3)队列的判空
当队列元素个数为零时,就是一个 空队,空队 不允许 出队 操作。
三、队列的顺序表实现
1、数据结构定义
对于顺序表,在 C语言 中表现为 数组,在进行 队列的定义 之前,我们需要考虑以下几个点:
1)队列数据的存储方式,以及队列数据的数据类型;
2)队列的大小;
3)队首指针;
4)队尾指针;
- 我们可以定义一个 队列 的 结构体,C语言实现如下所示:
#define DataType int // (1)
#define maxn 100005 // (2)
struct Queue { // (3)
DataType data[maxn]; // (4)
int head, tail; // (5)
};
-
(
1
)
(1)
(1) 用
DataType
这个宏定义来统一代表队列中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体 等等; -
(
2
)
(2)
(2)
maxn
代表我们定义的队列的最大元素个数; -
(
3
)
(3)
(3)
Queue
就是我们接下来会用到的 队列结构体; -
(
4
)
(4)
(4)
DataType data[maxn]
作为队列元素的存储方式,即 数组,数据类型为DataType
,可以自行定制; -
(
5
)
(5)
(5)
head
即队首指针,tail
即队尾指针,head == tail
代表空队;当队列非空时,data[head]
代表了队首元素(而队尾元素是不需要关心的);
2、入队
1、动画演示
如图所示,绿色元素 为新插入队尾的数据,执行完毕以后,队尾指针加一,队首指针不变。需要注意的是,顺序表实现时,队尾指针指向的位置是没有数据的,具体来看下代码实现。
2、源码详解
- 入队 操作,算上函数参数列表,总共也才几句话,代码实现如下:
void QueueEnqueue(struct Queue *que, DataType dt) { // (1)
que->data[ que->tail ] = dt; // (2)
que->tail = que->tail + 1; // (3)
}
-
(
1
)
(1)
(1)
que
是一个指向队列对象的指针,由于这个接口会修改队列对象的成员变量,所以这里必须传指针,否则,就会导致函数执行完毕,传参对象没有任何改变; - ( 2 ) (2) (2) 将传参的元素 入队;
- ( 3 ) (3) (3) 将 队尾指针 自增 1;
- 注意,这个接口在调用前,需要保证 队尾指针 小于 队列元素最大个数,即
que->tail < maxn
, - 如果 C语言 写的熟练,我们可以把 ( 2 ) (2) (2) 和 ( 3 ) (3) (3) 合成一句话,如下:
void QueueEnqueue(struct Queue *que, DataType dt) {
que->data[ que->tail++ ] = dt;
}
que->tail++
表达式的值是自增前的值,并且自身进行了一次自增。
3、出队
1、动画演示
如图所示,橙色元素 为原先的 队首元素,执行 出队 操作以后,黃色元素 成为当前的 队首元素,执行完毕以后,队首指针加一。由于是顺序表实现,队首元素前面的那些元素已经变成无效的了,具体来看下代码实现。
2、源码详解
- 出队 操作,只需要简单的改变,将 队首指针 加一 即可,代码实现如下:
void QueueDequeue(struct Queue* que) {
++que->head;
}
4、清空队列
1、动画演示
如图所示,对于数组来说,清空队列的操作只需要将 队首指针 和 队尾指针 都置零 即可,数据不需要清理,下次继续 入队 的时候会将之前的内存重复利用。
2、源码详解
- 清空队列的操作只需要将 队首指针 和 队尾指针 都归零即可,代码实现如下:
void QueueClear(struct Queue* que) {
que->head = que->tail = 0;
}
5、只读接口
- 只读接口包含:获取队首元素、获取队列大小、队列的判空,实现如下:
DataType QueueGetFront(struct Queue* que) {
return que->data[ que->head ]; // (1)
}
int QueueGetSize(struct Queue* que) {
return que->tail - que->head; // (2)
}
int QueueIsEmpty(struct Queue* que) {
return !QueueGetSize(que); // (3)
}
-
(
1
)
(1)
(1)
que->head
代表了 队首指针,即 队首下标,所以真正的 队首元素 是que->data[ que->head ]
; - ( 2 ) (2) (2) 因为只有在 入队 的时候,队尾指针 加一;出队 的时候,队首指针 加一;所以 队列元素个数 就是两者的差值;
- ( 3 ) (3) (3) 当 队列元素 个数为 零 时,队列为空。
- 如果还有不懂的问题,可以通过 「 博客主页 」找到作者的「 联系方式 」 ,线上沟通交流。
- 有关🌳《画解数据结构》🌳 的源码均开源,链接如下:《画解数据结构》
🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
闭关刷 LeetCode,剑指大厂Offer! 🌌《LeetCode 刷题指引》🌌
LeetCode 太简单?算法学起来! 💜《夜深人静写算法》💜
以上是关于画解数据结构:队列的主要内容,如果未能解决你的问题,请参考以下文章
❤️《画解数据结构》两万字,十张动图,画解双端队列❤️(建议收藏)