无向图
图是由一组顶点和一组能够将两个顶点相连的边组成的
采用邻接表数组的数据结构
无向图的API
public class | Graph | - |
---|---|---|
Graph(int v) | ||
Graph(In in) | ||
int | V() | 顶点数 |
int | E() | 边数 |
void | addEdge(int v, int w) | 添加边v-w |
Iterable | adj(int v) | 和v相邻的所有顶点 |
String | toString() |
深度优先搜索
寻找离起点更远的顶点,只在碰到死胡同时才访问近处的顶点
public class DepthFirstSearch{
private boolean[] marked;
private int count;
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); //递归
}
public boolean marked(int w){
return marked[w];
}
public int count(){
return count;
}
广度优先搜索
首先覆盖起点附近的顶点,只在临近的所有顶点都被访问了之后才向前前进
应用于寻找单点最短路径
public class BreadthFirstPaths {
private boolean[] marked;
private int[] edgeTo; //到达该顶点的已知路径上的最后一个顶点
private final int s; //起点
public BreadthFirstPaths(Graph g, int s){
marked = new boolean[g.V()];
edgeTo = new int[g.V()];
this.s = s;
bfs(g, s);
}
public void bfs(Graph g, int s){
Queue<Integer> queue = new Queue<>(); //先进先出
marked[s] = true;
queue.enqueue(s);
while(!queue.isEmpty()){
int v = queue.dequeue();
for(int w : g.adj(v)){
edgeTo[w] = v;
marked[w] = true;
queue.enqueue(w);
}
}
}
public boolean hasPathTo(int v){
return marked[v];
}
public Iterable<Integer> pathTo(int v){
if(!hasPathTo(v)) return null;
Stack<Integer> path = new Stack<>();
for(int x = v; x != s; x = edgeTo[x])
path.push(x);
path.push(s);
return path; //s-v最短路径
}
}
连通分量
在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通。如果图中任意两个顶点之间都连通,则称该图为连通图,否则,称该图为非连通图,则其中的连通子图称为连通分量
使用深度优先搜索找出图中的所有连通分量
public class CC {
private boolean[] marked;
private int count;
public int[] id; //算法实现基于一个由顶点索引的数组id[]
public CC(Graph g){
marked = new boolean[g.V()];
for(int s=0; s < g.V(); s++)
dfs(g,s);
count++; //连通分量标号count
}
private void dfs(Graph g, int v){
marked[v] = true;
id[v] = count; //可连接到的同属一个count
for(int w : g.adj(v))
if(!marked[w]) dfs(g, w); //递归
}
public boolean connected(int v, int w){
return id[v]==id[w];
}
public int count(){
return count;
}
}