一,问题描述
给出一个无向图,指定无向图中某个顶点作为源点。求出图中所有顶点到源点的最短路径。
无向图的最短路径其实是源点到该顶点的最少边的数目。
本文假设图的信息保存在文件中,通过读取文件来构造图。文件内容的格式参考这篇文章第一部分。
二,算法实现思路
无向图的最短路径实现相对于带权的有向图最短路径实现要简单得多。
源点的最短路径距离为0,从源点开始,采用广度优先的顺序,首先将与源点邻接的顶点的路径求出,然后再依次求解图中其他顶点的最短路径。
由于顶点的最短路径的求解顺序 是一个 广度优先的顺序,因此需要一个辅助队列。初始时,将源点的最短路径距离设置为0,将源点入队列。
然后,在一个while循环中,从队列中弹出顶点,遍历该顶点的邻接点,若该邻接点的距离未被更新过(表示该邻接点未被访问过),更新邻接点的最短路径距离为 该顶点的距离加上1,并将所有的邻接点入队列。
三,最短路径算法的实现
感觉该算法的实现与 二叉树的层序遍历,有向图的拓扑排序算法实现都非常的相似。他们都采用了广度的思想在里面。
广度优先的思想就是:处理完某个顶点后,去处理该顶点的所有邻接点,处理完它的邻接点后,再去处理更远(更外层)的顶点。
算法的代码如下:
1 /* 2 * 计算源点s到无向图中各个顶点的最短路径 3 * 需要一个队列来保存图中的顶点,初始时,源点入队列,然后以广度的形式向外扩散求解其他顶点的最短路径 4 */ 5 private void unweightedShortestPath(Vertex s){ 6 //初始化 7 Queue<Vertex> queue = new LinkedList<>(); 8 s.dist = 0; 9 queue.offer(s);//将源点dist设置为0并入队列 10 11 while(!queue.isEmpty()){ 12 Vertex v = queue.poll(); 13 for (Edge e : v.adjEdges) { //扫描v的邻接边(点) 14 if(e.endVertex.dist == Integer.MAX_VALUE){ //如果这个顶点(e.endVertex)未被访问(每个顶点只会入队列一次) 15 e.endVertex.dist = v.dist + 1;//更新该顶点到源点的距离 16 queue.offer(e.endVertex); 17 e.endVertex.preNode = v;//设置该顶点的前驱顶点 18 }//end if 19 }//end for 20 }//end while 21 }
第11行while循环,每个顶点出队列一次,第13行for循环,表示每条边被处理一次,故算法的时间复杂度为O(V+E)
第14行if语句表明,图中每个顶点只会入队列一次。因为,顶点入队列后,该顶点的 dist 设置为 v.dist+1,不再是 Integer.MAX_VALUE
四,完整代码实现
NonDirectedGraph.java构造图并实现最短路径算法