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

序号

算法名称

应用场景

1

修剪算法

减少树搜索过程中minimax算法评估的节点数量,属于对抗性搜索算法

2

算法

用于寻路和图遍历,在多个节点之间寻找路径,多用于点对点

3

算法

一种最佳优先图搜索算法,用于查找给定初始节点到任何目标节点的最低成本路径

4

回溯算法(backtracking)

通用算法,用于查找某些计算问题的所有可行解,特别是约束满足问题,逐步构建候选解,并在确定候选解不可行时进行回溯

5

波束搜索(beam) 算法

启发式搜索算法,通过扩展有限集中最可能的节点来探索图形

6

Bellman-Ford 算法

计算加权有向中单个源节点到其他节点的最短路径,比Dijkstra算法慢,但更通用

7

Best-first 算法

根据指定规则选择最可能的点来进行图搜索

8

双向(Bidirectional)搜索

从有向图中找出给定初始点到目标点的最短路径,进行两次搜索:一次从初始点开始向前搜索,一次从目标点向后搜索,相遇时停止

9

Boruvka算法

贪婪算法,从图中找到所有边缘权重不同的最小生成树或最小生成林

10

分支定界(Branch & Bound) 算法

通过状态空间搜索可行解

11

广度优先搜索BFS (Breadth-first search)

遍历或搜索树或图数据结构,从图任意节点开始,并在移动到下一节点之前探索当前深度水平的所有相邻节点

12

算法

增量搜索算法

13

深度优先搜索DFS(Depth-first search)

遍历或搜索树或图数据结构的算法,选择任意节点作为根节点,在回溯之前尽可能地沿着每个分支进行搜索

14

Dijkstra算法(SPF 算法, shortest path faster)

搜索节点之间的最短路径。单源最短路径搜索:给定初始点,搜寻初始点到其他点的最短路径,生成最短路径树

15

Edmonds算法

最小生成树的定向模拟

16

Floyd-Warshall算法

在具有正或负边缘权重的加权图中寻找最短路径

17

Fringe搜索

寻找从给定初始节点到目标节点之间的最低成本路径

18

爬山(Hill Climbing) 算法

从图的任意节点开始,然后尝试通过对节点进行增量更改来找到更好的节点

19

IDA (Iterative deepening

)算法

在加权图中找到从给定初始节点到一组目标节点中任意节点之间的最短路径

20

迭代深化搜索算法(Iterative deepening)

具有深度限制的深度优先搜索

21

Johnson算法

在稀疏边缘加权有向图中找到节点之间最短路径

22

跳跃点搜索JPS (Jump point)算法

算法优化版本

23

Kruskal 算法

最小生成树算法,找到联通树中任意两棵树的最小权重边缘

24

词典宽度有限搜索Lex-BFS算法

对图节点进行排序的线形时间搜索算法

25

LPA

算法

基于

算法的增量启发式搜索算法

26

Prim 算法

一种贪婪算法,用于从加权无向图中找到最小生成树

27

SMA

算法

使用有界内存的

算法,继承了

算法的特性

28

最短路径快速SPFA算法

Bellman-Ford算法的改进,在加权有向图中计算单源最短路径

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

一、深度优先搜索(Depth-first search)

深度优先搜索(DFS)是用于遍历或搜索图数据结构的算法,该算法从根节点开始(图搜索时可选择任意节点作为根节点)沿着每个分支进行搜索,分支搜索结束后在进行回溯。在进入下一节点之前,树的搜索尽可能的加深。

DFS的搜索算法如下(以二叉树为例):假定根节点(图的任意节点可作为根节点)标记为

,

(L) : 递归遍历左子树,并在节点

结束。

(R): 递归遍历右子树,并在节点

结束。

(N): 访问节点

这些步骤可以以任意次序排列。如果(L)在(R)之前,则该过程称为从左到右的遍历;反之,则称为从右到左的遍历。根据访问次序的不同,深度优先搜索可分为 pre-order、in-order、out-order以及post-order遍历方式。

1. Pre-order(NLR)遍历

(a)检查当前节点是否为空;

(b)展示根节点或当前节点数据;

(c)递归调用pre-order函数遍历左子树;

(d)递归调用pre-order函数遍历右子树。

pre-order遍历属于拓扑排序后的遍历,父节点总是在任何子节点之前被访问。该遍历方式的图示如下:

图1. pre-order遍历

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

2. In-order (LNR)遍历

(a)检查当前节点是否为空;

(b)递归调用in-order函数遍历左子树;

(c)展示根节点或当前节点数据;

(d)递归调用in-order函数遍历右子树。

在二叉树搜索中,in-order遍历以排序顺序访问节点数据。该遍历方式的图示如下:

图2. in-order遍历

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

3. Out-order (RNL)遍历

(a)检查当前节点是否为空;

(b)递归调用out-order函数遍历右子树;

(c)展示根节点或当前节点数据;

(d)递归调用out-order函数遍历左子树。

该遍历方式与LNR类似,但先遍历右子树后遍历左子树。仍然以图2为例,遍历次序依次为:H- I-G- F- B- E- D- C- A.

4. post-order (LRN)遍历

(a)检查当前节点是否为空;

(b)递归调用post-order函数遍历左子树;

(c)递归调用post-order函数遍历右子树;

(d)展示根节点或当前节点数据。

post-order遍历图示如下:

图3. 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遍历方式结合起来使用才可以描述树的独特性。

二、广度优先搜索(Breath-first search)

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

1945年,Konrad Zuse 在他被拒的博士论文中首次提到BFS在联通子图方面的应用。1972年,该博士论文被出版。1959年,Edward F. Moore对BFS进行重新设计,并用于寻找迷宫中的最短路径。 1961年,C.Y.Lee对算法进行开发作为电路路由算法。

BFS的遍历方法图示如下:

图4. BFS遍历

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

三、DFS与BFS的伪代码实现

1. DFS: pre-order 遍历

preorder(node)

if (node = null)

return

visit(node)

preorder(node.left)

preorder(node.right)

iterativePreorder(node)

if (node = null)

return

s ← empty stack

s.push(node)

while (not s.isEmpty())

node ← s.pop()

visit(node)

//right child is pushed first so that left is processed first

if (node.right ≠ null)

s.push(node.right)

if (node.left ≠ null)

s.push(node.left)

2. DFS:in-order遍历

inorder(node)

if (node = null)

return

inorder(node.left)

visit(node)

inorder(node.right)

iterativeInorder(node)

s ← empty stack

while (not s.isEmpty() or node ≠ null)

if (node ≠ null)

s.push(node)

node ← node.left

else

node ← s.pop()

visit(node)

node ← node.right

3. DFS: post-order遍历

postorder(node)

if (node = null)

return

postorder(node.left)

postorder(node.right)

visit(node)

iterativePostorder(node)

s ← empty stack

lastNodeVisited ← null

while (not s.isEmpty() or node ≠ null)

if (node ≠ null)

s.push(node)

node ← node.left

else

peekNode ← s.peek()

// if right child exists and traversing node

// from left child, then move right

if (peekNode.right ≠ null and lastNodeVisited ≠ peekNode.right)

node ← peekNode.right

else

visit(peekNode)

lastNodeVisited ← s.pop()

4. BFS

levelorder(root)

q ← empty queue

q.enqueue(root)

while (not q.isEmpty())

node ← q.dequeue()

visit(node)

if (node.left ≠ null)

q.enqueue(node.left)

if (node.right ≠ null)

q.enqueue(node.right)

四、DFS与BFS的R及Python代码实现

1. R语言实现DFS与BFS

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

1.1 R语言实现DFS:函数dfs

使用方法:

dfs(graph, root, neimode = c("out", "in", "all", "total"),

unreachable = TRUE, order = TRUE, order.out = FALSE,

father = FALSE, dist = FALSE, in.callback = NULL,

out.callback = NULL, extra = NULL, rho = parent.frame())

参数说明:

参数

含义

graph

输入图

root

根节点,搜索开始的单个节点

neimode

对有向图,指定访问边的类型。'out' 表示从节点出发的边,'in'表示进节点的边,'all' 完全忽略边的方向,'total' 与'all'相同。对于无向图,该参数可忽略

unreachable

逻辑值,取值'true'或'false', 表示搜索是否需要访问从根节点无法到达的节点集合

order

逻辑值,是否返回DFS排序后的节点序列

order.out

逻辑值,是否返回离开子图的节点排序

father

逻辑值,是否返回节点的父节点

dist

逻辑值,是否返回从根节点出发搜索的距离

in.callback

若不为空,则存在callback函数

out.callback

若不为空,则存在callback函数

extra

callback函数的其他参数

rho

callback函数被评估的环境

示例:

require(igraph)

## generate graph

graph

# plot graph

plot(graph)

# 搜索从根节点出发的节点排序

dfs_res

结果展示:

图5. 无向图示例

DFS R输出节点排序:

1-2-4-8-9-5-10-3-6-7-11-12-14-18-19-15-20-13-16-17

1.2 R语言实现BFS:函数bfs

使用方法:

bfs(graph, root, neimode = c("out", "in", "all", "total"),

unreachable = TRUE, restricted = NULL, order = TRUE,

rank = FALSE, father = FALSE, pred = FALSE, succ = FALSE,

dist = FALSE, callback = NULL, extra = NULL,

rho = parent.frame())

参数含义同dfs

示例:

require(igraph)

## generate graph

graph

# plot graph

plot(graph)

# 搜索从根节点出发的节点排序

bfs_res

succ=TRUE, dist=TRUE)

结果展示:

图6. 无向图示例

BFS R输出节点排序:

1-2-10-3-9-4-8-5-7-6-11-12-20-13-19-14-18-15-17-16

2. Python 实现BFS 及DFS

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

图7. 无向图示例

2.1 Python实现BFS

示例:

graph = {'A': set(['B', 'C']),

'B': set(['A', 'D', 'E']),

'C': set(['A', 'F']),

'D': set(['B']),

'E': set(['B', 'F']),

'F': set(['C', 'E'])}

def bfs_paths(graph, start, goal):

queue = [(start, [start])]

while queue:

(vertex, path) = queue.pop(0)

for next in graph[vertex] - set(path):

if next == goal:

yield path + [next]

else:

queue.append((next, path + [next]))

list(bfs_paths(graph, 'A', 'F'))

输出结果:

[['A', 'C', 'F'], ['A', 'B', 'E', 'F']]

2.2 Python实现DFS

示例:

graph = {'A': set(['B', 'C']),

'B': set(['A', 'D', 'E']),

'C': set(['A', 'F']),

'D': set(['B']),

'E': set(['B', 'F']),

'F': set(['C', 'E'])}

def dfs_paths(graph, start, goal):

stack = [(start, [start])]

while stack:

(vertex, path) = stack.pop()

for next in graph[vertex] - set(path):

if next == goal:

yield path + [next]

else:

stack.append((next, path + [next]))

list(dfs_paths(graph, 'A', 'F'))

输出结果:

[['A', 'C', 'F'], ['A', 'B', 'E', 'F']]

参考资料:

python 拓扑排序 dfs bfs_图遍历算法之DFS/BFS相关推荐

  1. python 拓扑排序 dfs bfs_拓扑排序的DFS和BFS

    博主以前有一个疑问,DFS和BFS各自的适用范围是?我想你今天看了这篇文章之后会有一个判断! BFS 数据结构与算法分析:c语言描述(p217) 已经存在一个Indgree入度数组(indgree[v ...

  2. 【算法】图(一)拓扑排序的实现 图的邻接表算法 判断是否图G中存在环

    文章目录 用list来表示图,判断是否存在环 邻接表实现拓扑排序 用DFS(邻接矩阵) 来实现拓扑排序. 判断无向图顶点是否全部连通 判断图G中从顶点u到v是否存在简单路径 输出图G中从顶点u到v的所 ...

  3. 拓扑排序以及迪杰斯特拉算法和弗洛伊德算法的一些例子(天勤数据结构)

    拓扑排序核心算法     在一个有向图中找到一个拓扑排序的过程如下:     1)从一个有向图中选择一个没有前驱(入度为0)的顶点输出:     2)删除1)中的顶点,并删除从该顶点出发的全部边:   ...

  4. 图论--拓扑排序--判断一个图能否被拓扑排序

    拓扑排序的实现条件,以及结合应用场景,我们都能得到拓扑排序适用于DAG图(Directed Acyclic Graph简称DAG)有向无环图, 根据关系我们能得到一个线性序列,实现的方式是DFS,具体 ...

  5. 数据结构上机实践第11周项目3 - 图遍历算法实现

    图遍历算法实现 本次实践将运用图结构基本算法库,进行遍历操作的实现,本次实践到的算法库点击此处参考.(编译环境:VC++6.0) 1.深度优先遍历--DFS 测试用图: 测试时用的图是,可以使用其他类 ...

  6. python 拓扑排序_Python 拓扑排序

    Python 拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G) ...

  7. python 拓扑排序 dfs bfs_bfs与dfs的优缺点?

    刚好今天作业有道题问了相似问题= =,顺便来回答一下 DFS和BFS主要差别在于BFS遍历方式是围绕着根结点一圈一圈(level by level)向外遍历,借助队列的方式实现,而DFS的方式则是从一 ...

  8. python 拓扑排序_拓扑排序(topsort)算法详解

    在图论中,由某个集合上的偏序得到全序的策略就是拓补排序算法.拓扑排序常出现在涉及偏序关系的问题中,例如时序的先后.事物的依赖等.针对这些问题拓扑排序通常能有效地给出可行解. 为了便于理解,我们先来看一 ...

  9. Robots on a Grid CodeForces - 1335F(拓扑排序+正反建图+判环)

    There is a rectangular grid of size n×m. Each cell of the grid is colored black ('0') or white ('1') ...

最新文章

  1. html分页首页上一页下一页,HTML静态分页(形如:首页,上一页,下一页,尾页)...
  2. 《js高程》 基本概念 上
  3. JavaScript语义基础
  4. 让 Chrome 崩溃的一行 CSS 代码
  5. codeforces 266B-C语言解题报告
  6. Flask学习记录之Flask-SQLAlchemy
  7. 华为手机怎么看图片属性_华为手机怎么才能息屏显示时间?操作方法很简单,看完涨知识了...
  8. 2022年中国母婴新消费白皮书
  9. 10个人有9个答错,另外1个只对一半:数据库的锁,到底锁的是什么?
  10. Eclipse 配置
  11. 源代码仓库选择-gitlab
  12. Qt中配置OpenCV
  13. 2022数学建模美赛回顾
  14. 使用浏览器查看UserAgent
  15. 王道数据结构代码---第五章:二叉树(重要)
  16. 台式计算机无线网卡怎么找,win7台式机找不到无线网卡怎么办
  17. windwos常用cmd(DOS)命令集合
  18. 什么是史诗、特性、用户故事和任务
  19. css实现立体长方柱
  20. 启动redis失败 Could not create server TCP listening socket 127.0.0.1:6379: bind: 操作成功

热门文章

  1. 没有躲过的坑--C++函数的默认参数(重新定义默认参数)
  2. Unsupervised Domain Adaptive Re-Identification: Theory and Practice阅读总结
  3. 手把手教你美国亚马逊直购
  4. Android兼容8.0后APP图标变为原生小机器人图标
  5. 一文看懂怎么用 Python 做数据分析
  6. Postman接口测试自动化介绍
  7. javaWeb-第一版
  8. BUG处理:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path buil
  9. 已知三角形三边求面积的c语言程序,已知三角形三边分别为4,5,6,求三角形的面积。用c语言编写程序...
  10. *关键字retry:很像goto语句,跳到标记处