对于图,我们一般有两种表示方法,稀疏图与稠密图。对于稠密图我们可以用一个二维数组来表示,而对于稀疏图,我们可以用一个集合类型的数组来存放,虽然表示方法不同,但是对它的操作都是一样的。下面我们来看一看对于图如何进行遍历,以及他能够解决哪些问题?
深度优先遍历:
1、下面我们对图进行深度优先遍历,顺便求图的联通分量,以及任意两点通过其他点是否是相连的?
public class Component {
private Graph graph; //图的引用
private boolean[] visited; //记录顶点是否被访问过
private int count=0; //记录图的联通分量
private int[] id; //用来判断图是否是相连的
public Integer getCount() {
return count;
}
/**构造函数*/
public Component(Graph graph) {
/**进行初始化*/
this.graph = graph;
visited = new boolean[graph.n()];
id = new int[graph.n()];
for(int i=0;i;i++){
visited[i] = false;
id[i] = -1;
}
/**从零开始对图进行遍历*/
for(int i = 0;i<graph.n();i++){
if(!visited[i]){
dfs(i);
count++; //联通分量加 1
}
}
}
/**递归实现dfs操作*/
private void dfs(int i) {
visited[i] = true;
id[i] = count;
for(Integer item:graph.adj(i)){
if(!visited[item]){
dfs(item);
}
}
}
/**判断图中任意两点是否相连*/
public boolean connected(int v, int w){
return id[v] == id[w];
}
}
2、解决第二个问题,计算从某一点到另一点的路径:
public class Path {
/**图的引用*/
private Graph G;
/**起始点*/
private int s;
/**记录dfs的过程中节点是否被访问*/
private boolean[] visited;
/**记录路径,表示我是从哪一个定点到我这儿的 */
private int[] from;
public Path(Graph graph, int s) {
this.G = graph;
visited = new boolean[graph.n()];
from = new int[G.n()];
for(int i=0;i<G.n();i++){
visited[i]=false;
from[i] = -1;
}
this.s = s;
dfs(s);
}
/***图的深度优先遍历*/
private void dfs(int v) {
visited[v]=true;
for(int i:G.adj(v)){
if(!visited[i]){
from[i]=v;
dfs(i);
}
}
}
/**查询从s点到w点的路径, 存放在vec中**/
public Vector path(int w){
Stack s = new Stack();
int p=w;
while(p!=-1){
s.push(p);
p=from[p];
}
Vector vector = new Vector<>();
while (!s.empty()){
vector.add(s.pop());
}
return vector;
}
/**打印路径*/
public void showPath(int w){
Vector vector = this.path(w);
for(int i=0;i;i++){
System.out.print(vector.elementAt(i));
if(i==vector.size()-1){
System.out.print("");
}
else{
System.out.print("->");
}
}
}
广度优先遍历:
3、当我们使用深度优先遍历寻找图示0到6的路径为:0->5->3->4->6,很显然这不是一条最短路径,那么如何找到最短路径呢?我们可以使用广度优先遍历,简称bfs(Breadth First Search)。同时我们还要借助于队列这种数据结构,下面我们来看一下思路
public class ShortestPath {
/**图的引用*/
private Graph G;
/**起始点*/
private int s;
/**记录bfs的过程中节点是否被访问*/
private boolean[] visited;
/**记录路径, from[i]表示查找的路径上i的上一个节点*/
private int[] from;
/**构造函数, 寻路算法, 寻找图graph从s点到其他点的路径*/
public ShortestPath(Graph graph, int s) {
this.G = graph;
this.s = s;
visited = new boolean[graph.n()];
from = new int[G.n()];
for(int i=0;i<G.n();i++){
visited[i]=false;
from[i] = -1;
}
Queue queue = new LinkedList();
queue.add(s);
visited[s]=true;
while(queue.size()!=0){
int a = queue.poll();
for(int i:graph.adj(a)){
if(!visited[i]){
queue.add(i);
visited[i] = true;
from[i] =a;
}
}
}
}
/**查询从s点到w点的路径, 存放在vec中**/
public Vector path(int w){
Stack s = new Stack();
int p=w;
while(p!=-1){
s.push(p);
p=from[p];
}
Vector vector = new Vector<>();
while (!s.empty()){
vector.add(s.pop());
}
return vector;
}
/**打印路径*/
public void showPath(int w){
Vector vector = this.path(w);
for(int i=0;i;i++){
System.out.print(vector.elementAt(i));
if(i==vector.size()-1){
System.out.print("");
}
else{
System.out.print("->");
}
}
System.out.println();
}
这样我们就能找到0-6的最短路径是0-6