当前位置:首页 » 操作系统 » 图的深度优先遍历算法

图的深度优先遍历算法

发布时间: 2023-12-01 18:00:53

⑴ 图遍历算法之DFS/BFS

在计算机科学, 图遍历(Tree Traversal,也称图搜索)是一系列图搜索的算法, 是单次访问树结构类型数据(tree data structure)中每个节点以便检查或更新的一系列机制。图遍历算法可以按照节点访问顺序进行分类,根据访问目的或使用场景的不同,算法大致可分为28种:

图遍历即以特定方式访问图中所有节点,给定节点下有多种可能的搜索路径。假定以顺序方式进行(非并行),还未访问的节点就需通过堆栈(LIFO)或队列(FIFO)规则来确定访问先后。由于树结构是一种递归的数据结构,在清晰的定义下,未访问节点可存储在调用堆栈中。本文介绍了图遍历领域最流行的广度优先搜索算法BFS和深度优先搜索算法DFS,对其原理、应用及实现进行了阐述。通常意义上而言,深度优先搜索(DFS)通过递归调用堆栈比较容易实现,广义优先搜索通过队列实现。

深度优先搜索(DFS)是用于遍历或搜索图数据结构的算法,该算法从根节点开始(图搜索时可选择任意节点作为根节点)沿着每个分支进行搜索,分支搜索结束后在进行回溯。在进入下一节点之前,树的搜索尽可能的加深。
DFS的搜索算法如下(以二叉树为例):假定根节点(图的任意节点可作为根节点)标记为 ,
(L) : 递归遍历左子树,并在节点 结束。
(R): 递归遍历右子树,并在节点 结束。
(N): 访问节点 。
这些步骤可以以任意次序排列。如果(L)在(R)之前,则该过程称为从左到右的遍历;反之,则称为从右到左的遍历。根据访问次序的不同,深度优先搜索可分为 pre-order、in-order、out-order以及post-order遍历方式。

(a)检查当前节点是否为空;
(b)展示根节点或当前节点数据;
(c)递归调用pre-order函数遍历左子树;
(d)递归调用pre-order函数遍历右子树。
pre-order遍历属于拓扑排序后的遍历,父节点总是在任何子节点之前被访问。该遍历方式的图示如下:

遍历次序依次为:F -B -A-D- C-E-G- I-H.

(a)检查当前节点是否为空;
(b)递归调用in-order函数遍历左子树;
(c)展示根节点或当前节点数据;
(d)递归调用in-order函数遍历右子树。
在二叉树搜索中,in-order遍历以排序顺序访问节点数据。该遍历方式的图示如下:

遍历次序依次为:A -B - C - D - E - F - G -H-I

(a)检查当前节点是否为空;
(b)递归调用out-order函数遍历右子树;
(c)展示根节点或当前节点数据;
(d)递归调用out-order函数遍历左子树。
该遍历方式与LNR类似,但先遍历右子树后遍历左子树。仍然以图2为例,遍历次序依次为:H- I-G- F- B- E- D- C- A.

(a)检查当前节点是否为空;
(b)递归调用post-order函数遍历左子树;
(c)递归调用post-order函数遍历右子树;
(d)展示根节点或当前节点数据。
post-order遍历图示如下:

遍历次序依次为:A-C-E-D-B-H-I-G-F.

pre-order遍历方式使用场景:用于创建树或图的副本;
in-order遍历使用场景:二叉树遍历;
post-order遍历使用场景:删除树

遍历追踪也称树的序列化,是所访问根节点列表。无论是pre-order,in-order或是post-order都无法完整的描述树特性。给定含有不同元素的树结构,pre-order或post-order与in-order遍历方式结合起来使用才可以描述树的独特性。

树或图形的访问也可以按照节点所处的级别进行遍历。在每次访问下一层级节点之前,遍历所在高层级的所有节点。BFS从根节点(图的任意节点可作为根节点)出发,在移动到下一节点之前访问所有相同深度水平的相邻节点。

BFS的遍历方法图示如下:

遍历次序依次为: F-B-G-A-D-I-C-E-H.

图算法相关的R包为igraph,主要包括图的生成、图计算等一系列算法的实现。

使用方法:

参数说明:

示例:

结果展示:

DFS R输出节点排序:

使用方法:

参数含义同dfs
示例:

结果展示:

BFS R输出节点排序:

以寻找两点之间的路径为例,分别展示BFS及DFS的实现。图示例如下:

示例:

输出结果:

示例:

输出结果:

[1] 维基网络: https://en.wikipedia.org/wiki/Tree_traversal
[2] GeeksforGeeks: https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
[3] http://webdocs.cs.ualberta.ca/~holte/T26/tree-traversal.html
[4]Martin Broadhurst, Graph Algorithm: http://www.martinbroadhurst.com/Graph-algorithms.html#section_1_1
[5]igraph: https://igraph.org/r/doc/dfs.html
[6]igraph: https://igraph.org/r/doc/bfs.html
[7] Depth-First Search and Breadth-First Search in python: https://eddmann.com/posts/depth-first-search-and-breadth-first-search-in-python/

⑵ 基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

        深度优先搜索和广度优先搜索,都是图形搜索算法,它两相似,又却不同,在应用上也被用到不同的地方。这里拿一起讨论,方便比较。

一、深度优先搜索

        深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

基本步奏

(1)对于下面的树而言,DFS方法首先从根节点1开始,其搜索节点顺序是1,2,3,4,5,6,7,8(假定左分枝和右分枝中优先选择左分枝)。

(2)从stack中访问栈顶的点;

(3)找出与此点邻接的且尚未遍历的点,进行标记,然后放入stack中,依次进行;

(4)如果此点没有尚未遍历的邻接点,则将此点从stack中弹出,再按照(3)依次进行;

(5)直到遍历完整个树,stack里的元素都将弹出,最后栈为空,DFS遍历完成。

二、广度优先搜索

        广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。

基本步奏

(1)给出一连通图,如图,初始化全是白色(未访问);

(2)搜索起点V1(灰色);

(3)已搜索V1(黑色),即将搜索V2,V3,V4(标灰);

(4)对V2,V3,V4重复以上操作;

(5)直到终点V7被染灰,终止;

(6)最短路径为V1,V4,V7.

⑶ 图遍历的算法

图的遍历方法目前有深度优先搜索法和广度(宽度)优先搜索法两种算法。 深度优先搜索法是树的先根遍历的推广,它的基本思想是:从图G的某个顶点v0出发,访问v0,然后选择一个与v0相邻且没被访问过的顶点vi访问,再从vi出发选择一个与vi相邻且未被访问的顶点vj进行访问,依次继续。如果当前被访问过的顶点的所有邻接顶点都已被访问,则退回到已被访问的顶点序列中最后一个拥有未被访问的相邻顶点的顶点w,从w出发按同样的方法向前遍历,直到图中所有顶点都被访问。其递归算法如下:
Boolean visited[MAX_VERTEX_NUM]; //访问标志数组
Status (*VisitFunc)(int v); //VisitFunc是访问函数,对图的每个顶点调用该函数
void DFSTraverse (Graph G, Status(*Visit)(int v)){
VisitFunc = Visit;
for(v=0; v<G.vexnum; ++v)
visited[v] = FALSE; //访问标志数组初始化
for(v=0; v<G.vexnum; ++v)
if(!visited[v])
DFS(G, v); //对尚未访问的顶点调用DFS
}
void DFS(Graph G, int v){ //从第v个顶点出发递归地深度优先遍历图G
visited[v]=TRUE; VisitFunc(v); //访问第v个顶点
for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w))
//FirstAdjVex返回v的第一个邻接顶点,若顶点在G中没有邻接顶点,则返回空(0)。
//若w是v的邻接顶点,NextAdjVex返回v的(相对于w的)下一个邻接顶点。
//若w是v的最后一个邻接点,则返回空(0)。
if(!visited[w])
DFS(G, w); //对v的尚未访问的邻接顶点w调用DFS
} 图的广度优先搜索是树的按层次遍历的推广,它的基本思想是:首先访问初始点vi,并将其标记为已访问过,接着访问vi的所有未被访问过的邻接点vi1,vi2,…, vi t,并均标记已访问过,然后再按照vi1,vi2,…, vi t的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,依次类推,直到图中所有和初始点vi有路径相通的顶点都被访问过为止。其非递归算法如下:
Boolean visited[MAX_VERTEX_NUM]; //访问标志数组
Status (*VisitFunc)(int v); //VisitFunc是访问函数,对图的每个顶点调用该函数
void BFSTraverse (Graph G, Status(*Visit)(int v)){
VisitFunc = Visit;
for(v=0; v<G.vexnum, ++v)
visited[v] = FALSE;
initQueue(Q); //置空辅助队列Q
for(v=0; v<G.vexnum; ++v)
if(!visited[v]){
visited[v]=TRUE; VisitFunc(v);
EnQueue(Q, v); //v入队列
while(!QueueEmpty(Q)){
DeQueue(Q, u); //队头元素出队并置为u
for(w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w))
if(!Visited[w]){ //w为u的尚未访问的邻接顶点
Visited[w]=TRUE; VisitFunc(w);
EnQueue(Q, w);
}
}
}
}

⑷ 简述深度优先搜索遍历的方法。

简述深度优先搜索遍历的方法?深度优先搜索算法(Depth-First-Search, DFS),最初是一种用于遍历或搜索树和图的算法,在LeetCode中很常见,虽然感觉不难,但是理解起来还是有点难度的。

简要概括,深度优先的主要思想就是“不撞南墙不回头”,“一条路走到黑”,如果遇到“墙”或者“无路可走”时再去走下一条路。

思路
假如对树进行遍历,沿着树的深度遍历树的节点,尽可能深的搜索树的分支,当达到边际时回溯上一个节点再进行搜索。如下图的一个二叉树。


首先给出这个二叉树的深度优先遍历的结果(假定先走左子树):1->2->4->5->3->6->7

那是怎样得到这样的结果呢?
根据深度优先遍历的概念:沿着这树的某一分支向下遍历到不能再深入为止,之后进行回溯再裤罩搭选定新的分支。

定义节点

class TreeNode{
int val;
TreeNode left;
TreeNode right;
}
递归的方式

分别对左右子树进行递归,一直到底才进行回溯。如果不了解递归可以参考我的博客你真胡拿的懂闷裤递归吗?。

class Solution{
public void (TreeNode root){
if(root == null){
return;
}
System.out.print(root.val +"->");
(root.left);
(root.right);
}
}
迭代的方式

上面实现了递归方式的深度优先遍历,也可以利用栈把递归转换为迭代的方式。

但是为了保证出栈的顺序,需要先压入右节点,再压左节点。

class Solution{
public void (TreeNode root){
if(root == null) return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
System.out.print(node.val + "->");
if(node.right != null){
stack.push(node.right);
}
if(node.left != null){
stack.push(node.left);
}
}
}
}
接着再列举个利用深度优先遍历的方式的题目

扫雷
给定一个表示游戏板的二维字符矩阵,'M'表示一个未挖出的地雷,'E'表示一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。

根据以下规则,返回相应位置被点击后对应的面板:

如果一个地雷('M')被挖出,游戏就结束了- 把它改为'X'。
如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。
如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。
如果在此次点击中,若无更多方块可被揭露,则返回面板。
示例

输入:

[['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'M', 'E', 'E'],
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

输出:

[['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]
思路:根据给定的规则,当给定一个Click坐标,当不为雷的时候以此坐标为基点向四周8个方向进行深度遍历,把空格E填充为B,并且把与地雷M相连的空方块标记相邻地雷的数量。

注意 :



在这个题中可以沿着8个方向递归遍历,所有要注意程序中,采用了两个for循环可以实现向8个方向递归。

⑸ Python算法系列—深度优先遍历算法

一、什么是深度优先遍历
深度优先遍历算法是经典的图论算法。从某个节点v出发开始进行搜索。不断搜索直到该节点所有的边都被遍历完,当节点v所有的边都被遍历完以后,深度优先遍历算法则需要回溯到v以前驱节点来继续搜索这个节点。
注意:深度优先遍历问题一定要按照规则尝试所有的可能才行。

二、二叉树

2.二叉树类型
二叉树类型:空二叉树、满二叉树、完全二叉树、完美二叉树、平衡二叉树。

空二叉树:有零个节点
完美二叉树:每一层节点都是满的二叉树(如1中举例的图)
满二叉树:每一个节点都有零个或者两个子节点
完全二叉树:出最后一层外,每一层节点都是满的,并且最后一层节点全部从左排列
平衡二叉树:每个节点的两个子树的深度相差不超过1.

注:国内对完美二叉树和满二叉树定义相同
3.二叉树相关术语
术语 解释
度 节点的度为节点的子树个数
叶子节点 度为零的节点
分支节点 度不为零的节点
孩子节点 节点下的两个子节点
双亲节点 节点上一层的源节点
兄弟节点 拥有同一双亲节点的节点
根 二叉树的源头节点
深度 二叉树中节点的层的数量

DLR(先序):
LDR(中序):
LRD(后序):
注意:L代表左子树R代表右子树;D代表根

6.深度优先遍历和广度优先遍历
深度优先遍历:前序、中序和后序都是深度优先遍历
从根节点出发直奔最远节点,
广度优先遍历:首先访问举例根节点最近的节点,按层次递进,以广度优先遍历上图的顺序为:1-2-3-4-5-6-7
三、面试题+励志
企鹅运维面试题:
1.二叉树遍历顺序:看上文
2.用你熟悉的语言说说怎么创建二叉树? python看上文

⑹ 用邻接表表示图进行深度优先遍历时,通常采用()来实现算法

使用栈来实现算法。

用邻接表表示图进行深度优先遍历时,通常采用栈来实现算法,广度遍历使用队列。

扩展材料:

深度优先遍历:类似与树的前序遍历。从图中的某个顶点v出发,访问此顶点,然后从v的未被访问到的邻接点进行遍历,直到图中所有和v有路径相通的顶点都被访问到

注:优先访问外层节点,访问到无新顶点时,会进行回退,访问未被访问过的分支顶点。

广度优先遍历:类似于树的层序遍历。从图中的某个顶点w出发,让顶点w入队,然后顶点w再出队,并让所有和顶点w相连的顶点入队,然后再出队一个顶点t,并让所有和t相连但未被访问过的顶点入队……由此循环,指定图中所有元素都出队。


参考资料来源:

知网论文-数据结构中图的遍历算法研究

热点内容
美国访问学者中介 发布:2024-11-30 01:49:47 浏览:491
手机版我的世界网易服务器地铁 发布:2024-11-30 01:38:57 浏览:522
pi币密码哪里看 发布:2024-11-30 01:25:12 浏览:670
哈利波特魔法觉醒如何找到服务器 发布:2024-11-30 01:20:44 浏览:179
为什么安卓商店里没有光遇 发布:2024-11-30 01:19:10 浏览:571
php注释符号 发布:2024-11-30 01:16:40 浏览:543
60乙醇用无水乙醇怎么配置 发布:2024-11-30 01:11:25 浏览:847
编程英语翻译 发布:2024-11-30 01:09:46 浏览:454
e425配置可交换显卡怎么弄 发布:2024-11-30 01:09:38 浏览:692
搜不到共享的文件夹 发布:2024-11-30 01:09:36 浏览:588