YEN--K最短路算法(K-Shortest-Path) Java实现
生活随笔
收集整理的這篇文章主要介紹了
YEN--K最短路算法(K-Shortest-Path) Java实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前段時間要做一個Project,在建模過程中發現要求出一個網絡拓撲中的前K條最短路才能進行后續的運算,自己研究了一段時間,實現了java版本的YEN--ksp算法。
Yen's算法是Yen 在1971 年提出的以其名字命名 的Yen 算法。Yen's算法基于偏離路徑算法思想,算法原理詳見https://en.wikipedia.org/wiki/Yen%27s_algorithm
我自己實現的這個算法比較粗糙,還有不少可以優化的地方,比如第一次Dijkstra(s)的時候可以把路徑信息存儲起來,以便后續無需計算直接使用,這里我就不實現了。
算法所需的數據采用隨機生成的方式,并且將設置YEN_ksp(0,55,50),即求出Node-0到Node-55的前50條最短路
package lib.utils; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; import java.util.Queue; import java.util.Random; public class Yen_Ksp {public static int n=100;//節點數public static double[][] edges=new double[n][n];public static double[][] edges_tmp=new double[n][n];public static ArrayList<Path> ans_path=new ArrayList<>();//K最短路徑public static Map<Path, Boolean> dev_path_sql=new HashMap<Path, Boolean>();//用于查詢偏離路徑是否重復public static Queue<Path> dev_path_queue = new PriorityQueue<>();//用于存放偏離路徑public static boolean[] s=new boolean[n];//待擴展的節點集合,false:未擴展public static int[] prev_node=new int[n];//存放前向節點public static double[] dist=new double[n];//路徑的權重和public static final double INF=10000000;public static void Dijkstra(int v0){//v0-> otherNodefor(int i=0;i<n;++i){//初始化dist[i]=edges_tmp[v0][i];s[i]=false;if(i!=v0&&dist[i]<INF) prev_node[i]=v0;else prev_node[i]=-1;}s[v0]=true;dist[v0]=0;for(int i=0;i<n-1;++i){//從頂點v0確定n-1條最短路徑(n-1個頂點)double min=INF;int u=v0;for(int j=0;j<n;++j){//選擇當前集合T中具有最短路徑的頂點 uif(!s[j]&&dist[j]<min){u=j;min=dist[j];}}s[u]=true;//將頂點u加入到集合s,表示它的最短路徑已求得for(int k=0;k<n;++k){if(!s[k]&&edges_tmp[u][k]<INF&&dist[u]+edges_tmp[u][k]<dist[k]){dist[k]=dist[u]+edges_tmp[u][k];prev_node[k]=u;}}}}//路徑信息存儲在path數組中(在前向節點集合中前向查找)public static ArrayList<Integer> getPath(int s,int t){ArrayList<Integer> v=new ArrayList<>();if(s==t) return v;v.add(t);int tmp=t;while(tmp!=s){tmp=prev_node[tmp];//tmp的前向節點v.add(tmp);}Collections.reverse(v);return v;}public static void set_link(ArrayList<Integer> p1,int s_node) {//p1:待檢測的path,s_node:p1的末結點int len=ans_path.size();int len_p=p1.size();for(int i=0;i<len;++i) {ArrayList<Integer> p2=ans_path.get(i).path;if(len_p>=p2.size()) continue;boolean flag=true;for(int j=0;j<len_p;++j) {if(p1.get(j)!=p2.get(j)) flag=false;;}if(flag==false) continue;//前面的path一樣,然后就看擴展結點的了for(int k=0;k<n;++k) {if(k!=s_node&&edges[s_node][k]!=INF) {//從s_node擴展結點kif(k==p2.get(len_p)) {//匹配成功,需將s_node->k 設置為INFedges_tmp[s_node][k]=INF;}}}}}public static void recover_link(int s_node) {for(int k=0;k<n;++k) {edges_tmp[s_node][k]=edges[s_node][k];}}public static void YEN_ksp(int s,int t,int k) {if(s==t||k<=0) return;//copyfor(int i=0;i<n;++i){for(int j=0;j<n;++j){edges_tmp[i][j]=edges[i][j];}}Dijkstra(s);Path p=new Path(getPath(s, t), dist[t]);//最短路,即迭代路徑while(k-->0) {if(!ans_path.contains(p)) ans_path.add(p);else continue;int len=p.path.size();ArrayList<Integer> path_tmp=new ArrayList<>();//p的部分迭代路徑for(int i=0;i<len-1;++i) {path_tmp.add(p.path.get(i));edges_tmp[p.path.get(i)][p.path.get(i+1)]=INF;set_link(path_tmp,p.path.get(i));Dijkstra(s);edges_tmp[p.path.get(i)][p.path.get(i+1)]=edges[p.path.get(i)][p.path.get(i+1)];recover_link(p.path.get(i));if(dist[t]>=INF) continue;//沒有路徑了Path pp=new Path(getPath(s,t),dist[t]);//修正后的最短路(偏離路徑) // if(!dev_path_sql.containsKey(pp)) { // dev_path_queue.add(pp); // dev_path_sql.put(pp.clone(), true); // }if(!dev_path_queue.contains(pp)) {dev_path_queue.add(pp);}}if(dev_path_queue.isEmpty()) break;p=dev_path_queue.remove();//dev_path_sql.remove(p);}}public static void main(String[] args) {Random r=new Random();//先生成一個樹edges[0][1]=r.nextDouble()*10+10;edges[1][0]=r.nextDouble()*10+10;for(int i=1;i<n;++i) {edges[i-1][i]=r.nextDouble()*10+10;edges[i][i-1]=r.nextDouble()*10+10; }//在樹上添加邊for(int i=0;i<n;++i) {for(int j=0;j<n;++j) {if(i==j) continue;if(edges[i][j]>0) {//已經有邊了//edges[i][j]+=r.nextDouble()*50+50;;}else {//沒邊if(r.nextDouble()>0) {//0.5的概率生成邊edges[i][j]=r.nextDouble()*100+500;}else {edges[i][j]=INF;}}}}System.out.println("YEN_ksp start:");YEN_ksp(0,55,50);//求出結點0到結點55的前50條最短路int len=ans_path.size();System.out.println(len);for(int i=0;i<len;++i) {int len_p=ans_path.get(i).path.size();for(int j=0;j<len_p;++j) {System.out.printf("%d ",ans_path.get(i).path.get(j));}System.out.printf("dist: %.3f\n",ans_path.get(i).dist);}// Dijkstra(1); // for(int i=0;i<n;++i) { // System.out.println(dist[i]); // }}}封裝的path.java:
package lib.utils;import java.util.ArrayList; import java.util.HashMap; import java.util.Map;public class Path implements Comparable,Cloneable{public ArrayList<Integer> path;double dist;public Path(ArrayList<Integer> path,double dist){this.path=path;this.dist=dist;}@Overridepublic int compareTo(Object o) {Path p=(Path)o;if(this.dist>p.dist) return -1;else if(this.dist==p.dist) return 0;else return 1;}@Overridepublic int hashCode() {return path.hashCode()+(int)dist;}@Overridepublic boolean equals(Object obj) {Path p=(Path)obj;if(this.dist!=p.dist) return false;int len1=this.path.size();int len2=p.path.size();if(len1!=len2) return false;for(int i=0;i<len1;++i) {if(this.path.get(i)!=p.path.get(i)) return false;}return true;}@Overrideprotected Path clone(){Path tmp;try {tmp=(Path) super.clone();}catch(CloneNotSupportedException e) {throw new RuntimeException("This calss not implement Cloneable");}tmp.path=(ArrayList<Integer>)this.path.clone();tmp.dist=this.dist;return tmp;} // public static void main(String[] args) { // Map<Path, Boolean> dev_path_sql=new HashMap<Path, Boolean>(); // ArrayList<Integer> v1= new ArrayList<>(); // v1.add(1); // v1.add(2); // ArrayList<Integer> v2= new ArrayList<>(); // v2.add(1); // v2.add(2); // Path p1=new Path(v1,10); // Path p2=new Path(v2,10); // dev_path_sql.put(p1.clone(), true); // System.out.println(dev_path_sql.containsKey(p2)); // p1.path.add(3); // System.out.println(dev_path_sql.containsKey(p2)); // dev_path_sql.put(new Path(v2,10), true); // System.out.println(dev_path_sql.size()); // dev_path_sql.remove(new Path(v2,10)); // System.out.println(dev_path_sql.size()); // } }運行結果如下:
YEN_ksp start: 50 0 1 55 dist: 521.530 0 53 54 55 dist: 563.921 0 56 55 dist: 567.054 0 57 56 55 dist: 567.667 0 59 58 57 56 55 dist: 573.120 0 52 53 54 55 dist: 574.652 0 50 51 52 53 54 55 dist: 586.064 0 58 57 56 55 dist: 589.331 0 55 dist: 590.887 0 54 55 dist: 613.887 0 47 48 49 50 51 52 53 54 55 dist: 626.572 0 60 59 58 57 56 55 dist: 644.148 0 49 50 51 52 53 54 55 dist: 649.717 0 51 52 53 54 55 dist: 652.126 0 65 64 63 62 61 60 59 58 57 56 55 dist: 656.914 0 48 49 50 51 52 53 54 55 dist: 676.458 0 63 62 61 60 59 58 57 56 55 dist: 687.190 0 62 61 60 59 58 57 56 55 dist: 688.555 0 61 60 59 58 57 56 55 dist: 689.318 0 44 45 46 47 48 49 50 51 52 53 54 55 dist: 694.788 0 64 63 62 61 60 59 58 57 56 55 dist: 695.797 0 66 65 64 63 62 61 60 59 58 57 56 55 dist: 703.198 0 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 705.473 0 46 47 48 49 50 51 52 53 54 55 dist: 723.243 0 45 46 47 48 49 50 51 52 53 54 55 dist: 734.643 0 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 738.297 0 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 740.333 0 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 749.203 0 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 761.700 0 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 769.119 0 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 780.547 0 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 784.978 0 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 793.785 0 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 800.300 0 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 802.399 0 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 810.460 0 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 813.899 0 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 818.640 0 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 829.547 0 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 831.752 0 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 832.565 0 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 836.453 0 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 841.897 0 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 852.720 0 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 867.588 0 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 874.265 0 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 876.927 0 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 880.461 0 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 884.851 0 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 886.536另一個基于鏈表的實現,詳見本人github:?https://github.com/xycodec/CodeCraft_2019_public/blob/master/src/main/java/com/huawei/graph/Graph.java#L470
總結
以上是生活随笔為你收集整理的YEN--K最短路算法(K-Shortest-Path) Java实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 结构化方法和面向对象方法的比较
- 下一篇: linux虚拟机硬盘扩容