图的遍历(BFS+DFS)
时间:2022-05-03
本文章向大家介绍图的遍历(BFS+DFS),主要内容包括宽度优先遍历、代码实现、深度优先遍历、代码实现、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
图的遍历与树的遍历基本类似,但要注意两个不同: 1. 图中可能有环路,因此可能会导致死循环; 2. 一个图可能由多个独立的子图构成,因此一条路径走到头后要重新选择尚未遍历的起点。
图的邻接表数据结构请参见:图的邻接表示法Java版
宽度优先遍历
思路
- 选择一个尚未访问的起点,依次访问它的相邻结点;
- 若相邻结点还有相邻结点的话,再依次访问尚未访问的相邻结点;直到以该结点为起点的这条路径上所有的结点都已访问;
- 再选择一个尚未访问的结点作为起点,重复上述操作,直到所有结点都已访问为止;
代码实现
/**
* 图的宽度优先遍历
* PS:本函数用于选择未访问的起点
* @param graph 图的邻接表
*/
public void BFS( Map<String,List<ENode>> graph ){
// 记录结点是否被访问
Map<String,Boolean> mark = new HashMap<>();
for( String node : graph.keySet() ){
mark.put( node, false );
}
for( String node : graph.keySet() ){
if ( !mark.get(node) ) {
// 选择一个起点
String start = graph.get(node).id;
BFS( graph, start );
}
}
}
/**
* 图的宽度优先遍历
* PS:本函数用于访问指定起点的路径上所有结点
* @param graph 图的邻接表
* @param start 起点
*/
private void BFS( Map<String,List<ENode>> graph, String start ){
Queue<String> queue = new LinkedList<>();
queue.offer( start );
while( !queue.isEmpty() ){
String curNode = queue.poll();// 取出一个结点
System.out.println(curNode);// 访问结点
mark.put(curNode,true);// 设为已访问
// 将相邻结点依次丢进queue
for( ENode edge : graph.get(curNode) ){
if ( !mark.get(edge.id) ) {
queue.offer( edge.id );
}
}
}
}
深度优先遍历
思路
寻找一个尚未访问的结点作为起点,依次访问它的相邻结点,直到所有的相邻结点都已访问,再回溯到上一层,访问上层结点的第二个相邻结点,每个结点的访问过程都要一条道走到黑。
代码实现
/**
* 图的深度优先遍历
* PS:本函数用于选择未访问的起点
* @param graph 图的邻接表
*/
public void DFS( Map<String,List<ENode>> graph ){
// 记录结点是否被访问
Map<String,Boolean> mark = new HashMap<>();
for( String node : graph.keySet() ){
mark.put( node, false );
}
for( String node : graph.keySet() ){
if ( !mark.get(node) ) {
// 选择一个起点
String start = graph.get(node).id;
DFS( graph, start );
}
}
}
/**
* 图的深度优先遍历
* PS:本函数用于访问某一结点为起点的所有相邻结点
* @param graph 图的邻接表
* @param start 起点
*/
public void DFS( Map<String,List<ENode>> graph, String start ){
// 访问起点
System.out.println(start);
// 标记为已访问
mark.put( start, true );
// 依次访问所有相邻结点
for( ENode edge : graph.get(start) ){
if ( !mark.get( edge.id ) ) {
String curNode = edge.id;
DFS(graph, curNode);
}
}
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法