对于图这种数据结构,一般有两种遍历即深度优先(dfs),和广度优先(bfs),假设我们有如下这张图:
访问过程
现在假设计算0到其它点的路径,根据广度优先遍历
,广度优先遍历需要借助于队列这种数据结构,思路分析:
注意:访问某一个顶点时,要进行标记是否被访问过以及其巧妙利用数组的索引跟顶点
计算路径
那如何找到顶点到某一点的路径?其实思路跟深度优先遍历中查找路径方法是一样的,但是在记录访问的数组中保存的数据却是不一样的(代码实现中from
数组),这就跟我们的遍历方式有关,深度优先遍历采用递归,广度优先遍历是借助于队列这种数据结构。
上述步骤我们可以这样记录(初始化数组的值为-1):arr[6]=0,arr[0]=-1,因此路径是0->6。同时我们也可以发现一个问题,这次我们一下就找到路径。以下是深度优先遍历(path)和广度优先遍历(path2)from
数组内部的数据
代码实现
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<Integer> queue = new LinkedList(); queue.add(s); //首先将0点加入队列 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<Integer> s = new Stack<Integer>(); int p=w; while(p!=-1){ s.push(p); p=from[p]; } Vector<Integer> 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<vector.size();i++){ System.out.print(vector.elementAt(i)); if(i==vector.size()-1){ System.out.print(""); } else{ System.out.print("->"); } } System.out.println(); } public static void main(String[] args) { Graph sparseGraph= new SparseGraph(7,false); ReadGraph read = new ReadGraph(); read.readGraph(sparseGraph,"demo/component3.txt"); ShortestPath path = new ShortestPath(sparseGraph,0); path.showPath(6); System.out.println("-------------------------------"); read.readGraph(sparseGraph,"demo/component3.txt"); Path path2 = new Path(sparseGraph,0); path2.showPath(6); }