0
点赞
收藏
分享

微信扫一扫

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列


文章目录

  • ​​一、数据结构的概念​​
  • ​​二、堆栈​​
  • ​​(3)具体eg:用堆栈实现倒序打印​​
  • ​​(4)我们也可以写一个递归函数做倒序打印,利用函数调用的栈帧实现后进先出​​
  • ​​三、深度优先搜索DFS​​
  • ​​1.用栈数据结构的DFS解决搜索迷宫问题​​
  • ​​2.迷宫问题引出的总结​​
  • ​​(6)回溯backtrack的思想​​
  • ​​(7)设计算法和设计数据结构这两件工作是紧密联系的​​
  • ​​3.习题​​
  • ​​四、广度优先搜索BFS​​
  • ​​1.用队列数据结构的BFS解决迷宫问题​​
  • ​​(3)BFS与DFS的区别​​
  • ​​2.习题​​
  • ​​(1)DFS为什么不能用队列?​​
  • ​​五、环形队列​​
  • ​​1.含义​​
  • ​​2.示意图如下​​
  • ​​3.BFS用环形队列实现需要分配多少个元素的空间​​

一、数据结构的概念

  • 数据的组织方式包含了存储方式和访问方式这两层意思,二者是紧密联系的
  • 数组的各元素是一个挨一个存储的,并且每个元素的大小相同,因此数组可以提供按下标访问的方式,结构体的各成员也是一个挨一个存储的,但是每个成员的大小不同,所以只能用.运算符加成员名来访问,而不能按下标访问。

二、堆栈

(1)堆栈与数组的区别
堆栈是一组元素的集合,类似于数组,不同之处在于,数组可以按下标随机访问,这次访问 a[5] 下次可以访问 a[1]

(2)堆栈的Push和Pop操作

  • 但是堆栈的访问规则被限制为Push和Pop两种操作,Push(入栈或压栈) 向栈顶添加元素,Pop(出栈或弹出) 则取出当前栈顶的元素,也就是说,只能访问栈顶元素而不能访问栈中其它元素。
  • 如果所有元素的类型相同,堆栈的存储也可以用数组来实现,访问操作可以通过函数接口提供。

(3)具体eg:用堆栈实现倒序打印

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_02


解释说明如下:

(a)数组 stack 是堆栈的存储空间,变量 top 总是保存数组中栈顶的下一个元素的下标,我们说“ top 总是指向栈顶的下一个元素”,或者把 top 叫做栈顶指针(Pointer) 。

(b)Pop操作的语义是取出栈顶元素,但上例的实现其实并没有清除原来的栈顶元素,只是把 top 指针移动了一下,原来的栈顶元素仍然存在那里,这就足够了,因为此后通过Push和Pop操作不可能再访问到已经取出的元素,下次Push操作就会覆盖它。 putchar 函数的作用是把一个字符打印到屏幕上,和 printf 的 %c 作用相同

(c)布尔函数 is_empty 的作用是防止Pop操作访问越界

(4)我们也可以写一个递归函数做倒序打印,利用函数调用的栈帧实现后进先出

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_03


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_04

三、深度优先搜索DFS

1.用栈数据结构的DFS解决搜索迷宫问题

(1)定义如下

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_05


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_06


(2)代码如下:

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_07


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_08


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_09


运行结果如下:

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_10


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_11


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_12


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_13

2.迷宫问题引出的总结

(1)这次堆栈里的元素是结构体类型的,用来表示迷宫中一个点的x和y座标.

(2)我们用一个新的数据结构保存走迷宫的路线,每个走过的点都有一个前趋(Predecessor) 点,表示是从哪儿走到当前点的,比如 predecessor[4][4] 是座标为(3, 4)的点,就表示从(3, 4)走到了(4, 4),一开始 predecessor 的各元素初始化为无效座标(-1, -1)。

(3)在迷宫中探索路线的同时就把路线保存在 predecessor 数组中,已经走过的点在 maze 数组中记为2防止重复走,最后找到终点时就根据 predecessor 数组保存的路线从终点打印到起点

(4)伪代码(Pseudocode)如下

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_14


(5)DFS的特点如下:

每次探索完各个方向相邻的点之后,取其中一个相邻的点走下去,一直走到无路可走了再退回来,取另一个相邻的点再走下去。这称为深度优先搜索(DFS,Depth First Search)

(6)回溯backtrack的思想

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_15


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_16

(7)设计算法和设计数据结构这两件工作是紧密联系的

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_17

3.习题

(1)

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_18

struct point q={0,0};
for (int q.row=0;q.row<MAX_ROW;q.row++)
for (int q.col=0;q.rcol<MAX_COL;q.col++)
{
if (predecessor[p.row][p.col].row != -1)
printf("(%d, %d)\n", q.row, q.col);
}

(2)

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_19


计算出row*MAX_ROW+col,把结果保存到predecessor数组,可节省一半的存储,需要座标

时可以用/MAX_ROW和%MAX_ROW运算把row和col分离出来.

四、广度优先搜索BFS

1.用队列数据结构的BFS解决迷宫问题

(1)队列,即FIFO,其特点如下

  • Enqueue(入队) 将元素添加到队尾
  • Dequeue(出队) 从队头取出元素并返回
  • 先来先服务,先入队的人也是先出队的

(2)程序如下

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_20


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_21


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_22


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_23


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_24


解释说明如下:

(a)BFS的数据结构如下所示:

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_25


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_26


(b)BFS的特点

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数据结构_27


广度优先是一种步步为营的策略,每次都从各个方向探索一步,将前线推进一步,图中的虚线就表示这个前线,队列中的元素总是由前线的点组成的,可见正是队列先进先出的性质使这个算法具有了广度优先的特点。

(3)BFS与DFS的区别

  • 广度优先搜索BFS还有一个特点是可以找到从起点到终点的最短路径,而深度优先搜索DFS找到的不一定是最短路径。
  • DFS的栈操作的 top 指针在Push时增大而在Pop时减小,因为栈空间是可以重复利用的
  • BFS的队列操作的 head 、 tail 指针都在一直增大,虽然前面的元素已经出队了,但它所占的存储空间却不能重复利用。出队的元素仍然有用,保存着走过的路径和每个点的前趋,但大多数程序并不是这样使用队列的,一般情况下出队的元素就不再有保存价值了。

2.习题

(1)DFS为什么不能用队列?

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_堆栈_28


因为出栈的元素被新入栈的元素覆盖了(2)

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_29


每个点最多入队一次,迷宫中有多少个点就最多需要多大的队列空间

五、环形队列

1.含义

  • 把 queue 数组想像成一个圈, head 和 tail 指针仍然是一直增大的,当指到数组末尾时就自动回到数组开头。
  • 就像两个人围着操场赛跑,沿着它们跑的方向看,从 head 到 tail 之间是队列的有效元素,从 tail 到 head 之间是空的存储位置,如果 head 追上 tail 就表示队列空了,如果 tail 追上 head 就表示队列的存储空间满了。

2.示意图如下

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_30

3.BFS用环形队列实现需要分配多少个元素的空间

(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_31


(第12章)LinuxC语言中栈、队列、DFS、BFS,循环队列_数组_32


举报

相关推荐

0 条评论