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 ans_path=new ArrayList<>();//K最短路径
	public static Map dev_path_sql=new HashMap();//用于查询偏离路径是否重复
	public static Queue 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-> otherNode
		for(int i=0;i getPath(int s,int t){
		ArrayList 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 p1,int s_node) {//p1:待检测的path,s_node:p1的末结点
		int len=ans_path.size();
		int len_p=p1.size();
		for(int i=0;i p2=ans_path.get(i).path;
			if(len_p>=p2.size()) continue;
			boolean flag=true;
			for(int j=0;jk 设置为INF
						edges_tmp[s_node][k]=INF;
					}
				}
			}
		}
	}
	
	public static void recover_link(int s_node) {
		for(int k=0;k0) {
			if(!ans_path.contains(p)) ans_path.add(p);
			else continue;
			int len=p.path.size();
			ArrayList path_tmp=new ArrayList<>();//p的部分迭代路径
			for(int i=0;i=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;i0) {//已经有边了
					//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

封装的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 path;
	double dist;
	public Path(ArrayList path,double dist){
		this.path=path;
		this.dist=dist;
	}
	
	@Override
	public 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;
	}
	
	@Override
	public int hashCode() {
		return path.hashCode()+(int)dist;
	}
	
	@Override
	public 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)this.path.clone();
		tmp.dist=this.dist;
		return tmp;
	}
//	public static void main(String[] args) {
//		Map dev_path_sql=new HashMap();
//		ArrayList v1= new ArrayList<>();
//		v1.add(1);
//		v1.add(2);
//		ArrayList 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

你可能感兴趣的:(java,程序设计,K最短路算法)