【算法4】4.1.无向图
无向图
无向图 API:
public abstract Graph {
Graph(int V); // 创建一个含有 V 个顶点的图
Graph(In in); // 从标准输入读取一幅图
int V(); // 顶点数
int E(); // 边数
void addEdge(int v, int w); // 添加一条边 v-w
Iterable<Integer> adj(int v); // 返回所有相邻顶点
String toString()
}
图的三种表示方法:
- 邻接矩阵:VxV 布尔矩阵(消耗空间大)
- 边的数组:Edge 数组(获取顶点的相邻顶点需要遍历所有边)
- 邻接表数组:一个以顶点为索引的数组,其值是顶点的相邻顶点列表(适合大型稀疏图)
图搜索算法
图搜索算法 API:
public class Search {
Search(Graph G, int s); // s 表示起点
boolean marked(int v); // s 和 v 是否连通
int count(); // 和 s 连通的顶点数
}
深度优先搜索算法用一个递归方法来遍历所有与起点连通的顶点,当方法访问顶点时:
- 标记顶点
- 递归访问未被标记的相邻顶点
// 深度优先搜索算法
public class DepthFirstSearch {
private boolean[] marked;
private int count;
// s 表示起点
public DepthFirstSearch(Graph G, int s) {
marked = new boolean[G.V()];
dfs(G, s);
}
// 深度优先搜索算法
private void dfs(Graph G, int v) {
marked[v] = true;
count++;
for (int w : G.adj(v)) {
if (!marked[w]) {
dfs(G, w);
}
}
}
// 顶点 v 是否与起点 s 连通
public boolean marked(int v) {
return marked[v];
}
// 与 s 连通的顶点数量
public int count() {
return count;
}
}
单点路径
路径 API:
public class Paths {
Paths(Graph G, int s);
boolean hasPathTo(int v);
Iterable<Integer> pathTo(int v);
}
基于深度优先搜索实现的单点路径:
// 路径 API
// 基于深度优先搜索算法实现
public class DepthFirstPaths {
private boolean[] marked;
private int[] pathTo;
private final int s;
// 找出所有与起点 s 连通的顶点到 s 的路径
public DepthFirstPaths(Graph G, int s) {
this.marked = new boolean[G.V()];
this.pathTo = new int[G.V()];
this.s = s;
dfs(G, s);
}
private void dfs(Graph G, int v) {
marked[v] = true;
for (int w : G.adj(v)) {
if (!marked[w]) {
pathTo[w] = v;
dfs(G, w);
}
}
}
// 起点 s 到顶点 v 是否存在一条路径
public boolean hasPathTo(int v) {
return marked[v];
}
// 如果起点 s 到顶点 v 存在路径,返回该路径
// 否则,返回 null
public Iterable<Integer> pathTo(int v) {
if (!hasPathTo(v)) {
return null;
}
Deque<Integer> deque = new ArrayDeque<>();
while (v != s) {
deque.push(v);
v = pathTo[v];
}
deque.push(s);
return CollectionUtils.dequeToStack(deque);
}
}
基于广度优先搜索实现的单点最短路径:
// 路径 API
// 基于广度优先搜索实现
public class BreadthFirstPaths {
private boolean[] marked;
private int[] pathTo;
private final int s;
// 找出所有与起点 s 连通的顶点到 s 的最短路径
public BreadthFirstPaths(Graph G, int s) {
this.marked = new boolean[G.V()];
this.pathTo = new int[G.V()];
this.s = s;
bfs(G, s);
}
// 广度优先搜索
private void bfs(Graph G, int s) {
Queue<Integer> queue = new ArrayDeque<>();
marked[s] = true;
pathTo[s] = s;
queue.add(s);
while (!queue.isEmpty()) {
int v = queue.remove();
for (int w : G.adj(v)) {
if (!marked[w]) {
marked[w] = true;
pathTo[w] = v;
queue.add(w);
}
}
}
}
// 是否存在从起点 s 到顶点 v 的路径
public boolean hasPathTo(int v) {
return marked[v];
}
// 如果起点 s 到顶点 v 存在路径,返回最短的一条
// 否则,返回 null
public Iterable<Integer> pathTo(int v) {
if (!hasPathTo(v)) {
return null;
}
Deque<Integer> deque = new ArrayDeque<>();
while (v != s) {
deque.push(v);
v = pathTo[v];
}
deque.push(s);
return CollectionUtils.dequeToStack(deque);
}
}