一、综述
图搜索算法是遍历图中每个节点的过程。我们根据其节点访问的顺序对其进行分类。下面我们将会介绍 广度优先遍历(Breadth-first Search 简称 bfs)、深度优先遍历(Depth-first Search 简称 dfs) 。这两个算法是图遍历的基础,也常用于数据的初步探索并且后续很多图寻路算法(Pathfinding Algorithm)都是基于此基础进行实现。
二、广度优先遍历
3.1 简介
遍历图算法BFS 是最常用的方法。
BFS 是一种遍历算法,选定一个节点(源或起始节点)开始遍历并逐层遍历图,从而探索邻居节点(直接连接到源节点的节点)。然后,您必须向下一级邻居节点移动。
正如 BFS 的名字所暗示的那样,您需要按如下方式遍历图:
- 先水平移动,访问当前层的所有节点
- 移动到下一层
以下图片为其遍历的顺序:
BFS 的时间复杂度为O(V + E),其中 V 是节点数,E 是边数。
3.2 代码
public void compute(int startId) {
System.out.println("=========== BFS ===========");
boolean[] visited = new boolean[graphApi.getVertexSize()];
//visited[startId] = true;
List<Integer> currentIds = new ArrayList<>();
currentIds.add(startId);
int depth = 1;
while (currentIds.size() != 0) {
Set<Integer> nextId = new HashSet<Integer>();
System.out.println("depth is " + (depth++) + " neighbors is " + currentIds);
for (Integer id : currentIds) {
if(visited[id]) {
continue;
}
visited[id] = true;
int[] edge = graphApi.getEdge(id);
if (edge != null) {
for (int eId : edge) {
nextId.add(eId);
}
}
}
currentIds.clear();
currentIds.addAll(nextId);
}
System.out.println("");
}
三、深度优先遍历
3.1. 简介
DFS算法是一种使用回溯思想的递归算法。如果可能,它涉及对所有节点进行详尽搜索,如果可能,则通过回溯。
在这里,单词 backtrack 意味着当你向前移动并且沿着当前路径没有更多节点时,你在同一路径上向后移动以找到要遍历的节点。将在当前路径上访问所有节点,直到遍历完所有未访问的节点,然后选择下一条路径。
DFS 的这种递归特性可以使用堆栈来实现。基本思想如下:
选择一个起始节点并将其所有相邻节点压入堆栈。
从堆栈中弹出一个节点以选择下一个要访问的节点并将其所有相邻节点推入堆栈。重复此过程,直到堆栈为空。但是,请确保已标记访问的节点。这将防止您多次访问同一个节点。如果您不标记访问过的节点并且您多次访问同一个节点,您可能会陷入无限循环。
以下图片为其遍历的顺序:
DFS 的时间复杂度为O(V + E),其中 V 是节点数,E 是边数。
3.2. 代码实现
1. 递归实现
public void dfs(int i, boolean[] visited, GraphApi graphApi) {
System.out.print(i);
visited[i] = true;
int[] edgeIds = graphApi.getEdge(i);
if (edgeIds == null) {
System.out.print(" -> ");
return;
} else {
System.out.print(" -> ");
}
for (int edgeId : edgeIds) {
if(!visited[edgeId]) {
dfs(edgeId, visited, graphApi);
}
}
}
2. 模拟堆栈实现
public void compute(int i, boolean[] visited) {
Stack<Integer> stack = new Stack<>();
// 根节点压栈
stack.push(i);
visited[i] = true;
while (!stack.isEmpty()) {
Integer id = stack.pop();
System.out.print(id + " -> ");
// 逻辑处理
int[] edge = graphApi.getEdge(id);
if(edge != null) {
for (int item : edge) {
if(!visited[item]) {
stack.push(item);
visited[item] = true;
}
}
}
}
}
详细源代码地址:
https://github.com/RoadTLife/TGraph