本文最后更新于:2022年5月20日 下午
摘要:图的遍历两种方式:深度优先搜索和广度优先搜索。
图的遍历
从图的某一顶点出发访问图中其余顶点,且每一个顶点仅被访问一次
- 广度优先搜索(Breadth First Search,BFS),又称为宽度优先搜索,横向优先搜索
- 深度优先搜索(Depth First Search,DFS)
广度优先搜索
广度优先搜索与二叉树的层序遍历类似,优先访问当前顶点的所有相邻顶点。
实现:使用队列
- 给定一个开始的顶点,加入队列,然后弹出
- 每弹出一个顶点,把该顶点所有没有入队的顶点加入队列,为了记录哪些顶点未入队,可以使用一个Set,当顶点入队时加入Set中
- 直到队列为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void bfs(K begin) { Vertex<K, E> vertex = vertices.get(begin); if (vertex == null) throw new IllegalArgumentException("不存在该节点");
Queue<Vertex<K, E>> queue = new LinkedList<>(); Set<K> visited = new HashSet<>(); queue.offer(vertex); visited.add(vertex.key); while (!queue.isEmpty()) { vertex = queue.poll(); System.out.println(vertex); vertex.outEdges.forEach(edge -> { if (!visited.contains(edge.to.key)) { queue.offer(edge.to); visited.add(edge.to.key); } }); } }
|
深度优先搜索
深度优先遍历,是对先序遍历的推广,从某个顶点v开始处理,然后递归地便利所有与v邻接的顶点。
实现:使用栈
- 给定一个开始的顶点,压入栈中,然后弹出
- 没弹出一个顶点,把该顶点下一个没有入栈的邻接顶点压入栈中
- 直到栈为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public void dfs(K begin) { Vertex<K, E> vertex = vertices.get(begin); if (vertex == null) throw new IllegalArgumentException("不存在该节点");
Stack<Vertex<K, E>> stack = new Stack<>(); Set<K> visited = new HashSet<>(); stack.push(vertex); System.out.println(vertex); visited.add(vertex.key); while (!stack.isEmpty()) { vertex = stack.pop(); for (Edge<K, E> edge : vertex.outEdges) { if (!visited.contains(edge.to.key)) { stack.push(vertex); stack.push(edge.to); visited.add(edge.to.key); System.out.println(edge.to); break; } } } }
|
遍历的访问器
以上的遍历实现,都是直接打印顶点信息,但是有时候,遍历图可能需要进行其他操作,这就需要定义一个接口,具体执行怎样的操作,可以实现该接口中的方法。
- 定义一个访问器接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.shg.graph;
@FunctionalInterface public interface GraphVisitor<K> {
void visit(K k); }
|
- 重载bfs和dfs方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public void bfs(K begin, GraphVisitor<K> visitor) { Vertex<K, E> vertex = vertices.get(begin); if (vertex == null) throw new IllegalArgumentException("不存在该节点");
Queue<Vertex<K, E>> queue = new LinkedList<>(); Set<K> visited = new HashSet<>(); queue.offer(vertex); visited.add(vertex.key); while (!queue.isEmpty()) { vertex = queue.poll(); visitor.visit(vertex.key); vertex.outEdges.forEach(edge -> { if (!visited.contains(edge.to.key)) { queue.offer(edge.to); visited.add(edge.to.key); } }); } }
public void dfs(K begin, GraphVisitor<K> visitor) { Vertex<K, E> vertex = vertices.get(begin); if (vertex == null) throw new IllegalArgumentException("不存在该节点");
Stack<Vertex<K, E>> stack = new Stack<>(); Set<K> visited = new HashSet<>(); stack.push(vertex); visitor.visit(vertex.key); visited.add(vertex.key); while (!stack.isEmpty()) { vertex = stack.pop(); for (Edge<K, E> edge : vertex.outEdges) { if (!visited.contains(edge.to.key)) { stack.push(vertex); stack.push(edge.to); visited.add(edge.to.key); visitor.visit(edge.to.key); break; } } } }
|
图数据结构与算法汇总