图的遍历
BFS 广度优先搜索
从一个顶点出发,宽度优先遍历
注意:对于有向图来说,选择第一个顶点很重要;因为不一定能够每个节点都能遍历到
BFS实现思路
和二叉树的层序遍历的思路基本一致;当节点出队的时候,将子节点放进队列;
但是要注意对于已经进入过队列的节点,不再入队
实现代码:
@Override
public void bfs(V begin, vertexVisitor<V> visitor) {
Vertex<V, E> beginVertex = vertices.get(begin);
if(beginVertex == null) return;
//1.准备队列,和存储已经遍历过的节点
Queue<Vertex<V,E>> que = new LinkedList<>();
HashSet<Vertex<V, E>> set = new HashSet<>();
//2.初始化
que.offer(beginVertex);
set.add(beginVertex);
//注意:在元素入队的时候就加到set中去,出队的时候添加会有问题
while(!que.isEmpty()){
Vertex<V, E> poll = que.poll();
if(visitor.visit(poll.value)) return; //返回true表示停止遍历
for (Edge<V, E> outEdge : poll.outEdges) {
if(!set.contains(outEdge.to)){
que.offer(outEdge.to);
set.add(outEdge.to);
}
}
}
}
深度优先搜索(DFS)
DFS是一种回溯算法
注:DFS结果不唯一
如果当前节点的outVertex都是访问过的,就退回到上一个vertex
DFS 递归实现
1进去,打印1
然后3进去,打印3
然后7进去,打印7
7执行完后,没有路了,退到3
3也没有路可以走了,退到1
@Override
public void dfs(V begin, vertexVisitor<V> visitor) {
Vertex<V, E> beginVertex = vertices.get(begin);
if(beginVertex == null) return;
dfs(beginVertex,visitor,new HashSet<>()); //这个hashSet是递归调用过程中所有方法共享的
}
private void dfs(Vertex<V,E> vertex, vertexVisitor<V> visitor,Set<Vertex<V,E>> visitedVertices){
visitor.visit(vertex.value);
visitedVertices.add(vertex);
for (Edge<V, E> outEdge : vertex.outEdges) {
if(visitedVertices.contains(outEdge.to)) continue;
dfs(outEdge.to,visitor,visitedVertices);
}
}
DFS非递归思路
非递归替代递归,肯定要用栈;
以边为单位,进行遍历;栈顶元素出栈的时候,将一条边的两个元素都给压栈
DFS非递归实现
public void dfs2(V begin, vertexVisitor<V> visitor) {
Vertex<V, E> beginVertex = vertices.get(begin);
if (beginVertex == null) return;
HashSet<Vertex<V, E>> visitedVertices = new HashSet<>();
LinkedList<Vertex<V, E>> stack = new LinkedList<>();
stack.push(beginVertex);
visitor.visit(beginVertex.value);
visitedVertices.add(beginVertex);
while(!stack.isEmpty()){
Vertex<V, E> peek = stack.pop();
for (Edge<V, E> outEdge : peek.outEdges) {
if(visitedVertices.contains(outEdge.to)) continue;
stack.push(outEdge.from);
stack.push(outEdge.to);
visitedVertices.add(outEdge.to);
//System.out.println(outEdge.to.value);
visitor.visit(outEdge.to.value);
break;
}
}
}