圖的遍歷方式
圖的遍歷:從圖中某一頂點出發訪問圖中其餘頂點,且每一個頂點僅被訪問一次。
圖有2種常見的遍歷方式(有向圖、無向圖都適用)
- 廣度優先搜索(Breadth First Search,BFS),又稱爲寬度優先搜索、橫向優先搜索
- 深度優先搜索(Depth First Search,DFS)
廣度優先搜索
廣度優先搜索:從起始節點開始一層一層的進行遍歷,只有完全遍歷完一層所有的節點後纔會進入下一層的遍歷。二叉樹的層序遍歷就是一種廣度優先搜索。
Graph<V, E>接口中添加內部接口:
interface Visitor<V> {
boolean visit(V v);
}
代碼實現如下:
public void bfs(V begin, Visitor<V> visitor) {
// 根據值獲取起始頂點
Vertex<V, E> beginVertex = vertices.get(begin);
if(Objects.isNull(beginVertex)) {
return;
}
Queue<Vertex<V, E>> queue = new LinkedList<>();
Set<Vertex<V, E>> visitedVertices = new HashSet<>(); // 記錄已經添加入隊列中的頂點
queue.offer(beginVertex);
visitedVertices.add(beginVertex);
while (!queue.isEmpty()) {
Vertex<V, E> vertex = queue.poll();
// 返回true終止遍歷
if(visitor.visit(vertex.value)) {
return;
}
vertex.outEdges.forEach(edge -> {
if(!visitedVertices.contains(edge.toVertex)) {
queue.offer(edge.toVertex);
visitedVertices.add(edge.toVertex);
}
});
}
}
深度優先搜索
深度優先搜索:從起始節點沿着樹的深度遍歷樹的節點,儘可能深的搜索樹的分支。當節點v的所在邊都己被探尋過或者無法繼續往下搜索時,搜索將回溯到發現節點v的那條邊的起始節點,整個進程反覆進行直到所有節點都被訪問爲止。二叉樹的前序遍歷就是一種深度優先搜索。
遞歸實現
public void dfs(V begin, Visitor<V> visitor) {
// 根據值獲取起始頂點
Vertex<V, E> beginVertex = vertices.get(begin);
if(Objects.isNull(beginVertex)) {
return;
}
// 遞歸調用
dfs(beginVertex, visitor, new HashSet<>());
}
// dfs返回true,中斷遍歷
private boolean dfs(Vertex<V, E> vertex, Visitor<V> visitor, Set<Vertex<V, E>> visitedVertices) {
if(visitor.visit(vertex.value)) {
return true;
}
visitedVertices.add(vertex);
Iterator<Edge<V, E>> iterator = vertex.outEdges.iterator();
while (iterator.hasNext()) {
Edge<V, E> edge = iterator.next();
if(!visitedVertices.contains(edge.toVertex)) {
if(dfs(edge.toVertex, visitor, visitedVertices)) {
return true;
}
}
}
return false;
}
迭代實現
public void dfs(V begin, Visitor<V> visitor) {
// 根據值獲取起始頂點
Vertex<V, E> beginVertex = vertices.get(begin);
if (Objects.isNull(beginVertex)) {
return;
}
Set<Vertex<V, E>> visitedVertices = new HashSet<>();
Stack<Vertex<V, E>> stack = new Stack<>();
stack.push(beginVertex);
visitedVertices.add(beginVertex);
if(visitor.visit(beginVertex.value)) {
return;
}
while (!stack.isEmpty()) {
Vertex<V, E> vertex = stack.pop();
Iterator<Edge<V, E>> iterator = vertex.outEdges.iterator();
while (iterator.hasNext()) {
Edge<V, E> edge = iterator.next();
if(!visitedVertices.contains(edge.toVertex)) {
stack.push(vertex);
stack.push(edge.toVertex);
visitedVertices.add(edge.toVertex);
if(visitor.visit(edge.toVertex.value)) {
return;
}
break;
}
}
}
}
更多精彩內容關注本人公衆號:架構師升級之路