从图中某一个顶点出发访问图中其余顶点,且每个顶点仅被访问一次.
本文的代码基于我之前的文章图
广度优先搜索(BFS)
BFS实现思路
需要借助队列数据结构,每次某个顶点出队,都需要把顶点所有出度边的终点入队列,如图:
代码实现:
public void bfs(V begin) {
//获取该顶点
Vertex<V, E> beginVertex = vertices.get(begin);
if (beginVertex == null) {
return;
}
//保存之前访问过的节点
Set<Vertex<V, E>> visitedVertices = new HashSet<>();
//队列
Queue<Vertex<V, E>> queue = new LinkedList<>();
//顶点入队
queue.offer(beginVertex);
//加入已访问集合
visitedVertices.add(beginVertex);
while (!queue.isEmpty()) {
Vertex<V, E> vertex = queue.poll();
//打印节点
System.out.println(vertex.value);
//把该顶点出度边的终点加入队列
for (Edge<V, E> edge : vertex.outEdges) {
//如果该顶点已经访问,则退出
if (visitedVertices.contains(edge.to)) {
continue;
}
queue.offer(edge.to);
visitedVertices.add(edge.to);
}
}
}
深度优先搜索(DFS)
沿着一条分支一路遍历到底,直到没有可以遍历的节点,再一层层后退,看哪个分支还有节点可以遍历,之前遍历的节点不可重复遍历.
递归实现
代码:
public void dfs(V begin) {
//获取该顶点
Vertex<V, E> beginVertex = vertices.get(begin);
if (beginVertex == null) {
return;
}
dfs(beginVertex, new HashSet<>());
}
private void dfs(Vertex<V, E> vertex, HashSet<Vertex<V, E>> visitedVertices) {
System.out.println(vertex.value);
visitedVertices.add(vertex);
//遍历节点的出度,对出度边的顶点继续dfs
for (Edge<V, E> edge : vertex.outEdges) {
//如果已经遍历了.就不再遍历
if (visitedVertices.contains(edge.to)) {
continue;
}
//递归继续遍历
dfs(edge.to, visitedVertices);
}
}
递归实现其实和二叉树的递归遍历很相似.
非递归实现
代码:
public void dfs(V begin) {
//获取该顶点
Vertex<V, E> beginVertex = vertices.get(begin);
if (beginVertex == null) {
return;
}
//保存之前访问过的节点
Set<Vertex<V, E>> visitedVertices = new HashSet<>();
//栈
Stack<Vertex<V, E>> stack = new Stack<>();
//访问顶点
stack.push(beginVertex);
System.out.println(beginVertex.value);
visitedVertices.add(beginVertex);
while (!stack.isEmpty()) {
Vertex<V, E> vertex = stack.pop();
for (Edge<V, E> edge : vertex.outEdges) {
//判断是否访问过
if (visitedVertices.contains(edge.to)) {
continue;
}
stack.push(edge.from);
stack.push(edge.to);
System.out.println(edge.to.value);
visitedVertices.add(edge.to);
break;
}
}
}