博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法导论——所有点对最短路径:稀疏图Johnson算法
阅读量:5968 次
发布时间:2019-06-19

本文共 3708 字,大约阅读时间需要 12 分钟。

hot3.png

package org.loda.graph;import org.loda.structure.Stack;import org.loda.util.In;/** *  * @ClassName: Johnson 时间复杂度:EVlgV * @Description: 稀疏图上的johnson算法,由于稀疏图的数据结构推荐使用邻接链表,所以这里也采用邻接链表,该算法也是给稀疏图使用的,如果是密集图,推荐使用实现较为简单的FloydWashall算法,可以保证V^3的时间复杂度 *  * Johnson算法使用的方式相当于给每个边都加了一个权重,使得所有边都为非负数,这样就能对每个边使用较为高效的Dijkstra算法。 * 注意的是不能简单的给每个边加相同的值然后使得所有边都变成非负数,原因为假设从a->b有两条路径,一条权重为1+1,一条为2,本应权重和相等;如果都加1,则变成了2+2和3,不一致了,就会导致更新了不该更新的边 *  * Johnson比较巧妙的引入了h函数来解决这个问题,通过这个函数进行每个边的重新赋值权重 *  * @author minjun * @date 2015年6月2日 下午5:49:13 *  */public class Johnson {	/**	 * 权重函数h 用来重新赋予权重的函数,利用数组存储每个i对应的权重函数值	 */	private double[] h;	/**	 * 距离	 */	private double[][] dist;	/**	 * 前驱节点	 */	private int[][] prev;	/**	 * 是否含有负环	 */	private boolean negativeCycle;	@SuppressWarnings("unchecked")	public Johnson(WeightDigraph g) {		int v = g.v();		h = new double[v];		dist = new double[v][v];		prev = new int[v][v];		// 先进行一次BellmanFord算法,用来判断是否存在负环,如果存在则停止计算最短路径		BellmanFord bf = new BellmanFord(g, 0);		if (bf.hasNegCycle()) {			negativeCycle = true;			System.out.println("有负环,不存在最短路径...");			return;		}		/**		 * 利用Johnson算法计算最短路径		 */		computeShortestPath(g);	}	public void computeShortestPath(WeightDigraph g) {		int v = g.v();		// 创建一个新的图G,G含有一个多余的顶点s'作为原点计算h函数(目前将s'设为索引为v的顶点)		WeightDigraph G = new WeightDigraph(v + 1);		for (int i = 0; i < v; i++) {			// 将新的顶点v和其他节点相连,并将他们的距离设为0			G.add(v, i, 0);			for (Edge e : g.adj(i)) {				int j = e.otherSide(i);				G.add(i, j, e.weight());			}		}		int V = G.v();		BellmanFord bf = new BellmanFord(G, V - 1);		// 为权重函数赋值		for (int i = 0; i < v; i++) {			h[i] = bf.distTo(i);		}		WeightDigraph wg = new WeightDigraph(v);		//创建一个新的图,将所有更新权重后的节点和边加到该图中,这时的图为非负权重图,可以对他使用Dijkstra算法		for (int i = 0; i < v; i++) {			for (Edge e : g.adj(i)) {				int j = e.otherSide(i);				wg.add(i, j, e.weight() + h[i] - h[j]);			}		}		for (int i = 0; i < v; i++) {			//对每个节点使用Dijkstra算法			Dijkstra d = new Dijkstra(wg, i);			for (int j = 0; j < v; j++) {				//由于每个边都加了一定的权重,这里为了还原到原始距离,就将增加的权重减去				dist[i][j] = d.distTo(j) + h[j] - h[i];				d.pathTo(i);				prev[i]=d.prev;			}		}			}	/**	 * 	 * @Title: hasNegtiveCycle	 * @Description: 是否含有负环	 * @param @return 设定文件	 * @return boolean 返回类型	 * @throws	 */	public boolean hasNegtiveCycle() {		return negativeCycle;	}	/**	 * 	 * @Title: distTo	 * @Description: i->j的距离	 * @param @param i	 * @param @param j	 * @param @return 设定文件	 * @return double 返回类型	 * @throws	 */	public double distTo(int i, int j) {		return dist[i][j];	}	 public Iterable
pathTo(int i,int j){ int[] p=prev[i]; Stack
path=new Stack
(); for(int m=j;m!=i;m=p[m]){ path.push(m); } path.push(i); return path; } public static void main(String[] args) { // 不含负权重环的文本数据 String text1 = "F:\\算法\\attach\\tinyEWDn.txt"; // 含有负权重环的文本数据 String text2 = "F:\\算法\\attach\\tinyEWDnc.txt"; WeightDigraph g = new WeightDigraph(new In(text1)); Johnson d = new Johnson(g); if (d.hasNegtiveCycle()) { System.out.println("该有向加权图含有负权重环,不存在最短路径"); } else { int s = 0; for (int i = 0; i < g.v(); i++) { System.out .println("从原点" + s + "到" + i + "距离为" + d.distTo(s, i)+",路径为:"); for(int m:d.pathTo(s, i)){ System.out.print(m+"->"); } System.out.println(); } } }}

如果采用负环图,打印结果为:

有负环,不存在最短路径...该有向加权图含有负权重环,不存在最短路径

如果采用非负环图,打印结果为:

从原点0到0距离为0.0,路径为:0->从原点0到1距离为0.93,路径为:0->2->7->3->6->4->5->1->从原点0到2距离为0.26,路径为:0->2->从原点0到3距离为0.9900000000000001,路径为:0->2->7->3->从原点0到4距离为0.26000000000000023,路径为:0->2->7->3->6->4->从原点0到5距离为0.6100000000000001,路径为:0->2->7->3->6->4->5->从原点0到6距离为1.5100000000000002,路径为:0->2->7->3->6->从原点0到7距离为0.6000000000000001,路径为:0->2->7->

转载于:https://my.oschina.net/u/1378920/blog/424028

你可能感兴趣的文章
Exchange Server 2010部署安装之一
查看>>
Nsrp实现juniper防火墙的高可用性【HA】!
查看>>
oracle11g 安装在rhel5.0笔记
查看>>
解决Lync 2013演示PPT提示证书问题的多种方法
查看>>
[转]经典正则表达式
查看>>
JDBC+Servlet+JSP整合开发之26.JSP内建对象
查看>>
【下载】深入oracle数据库专用虚拟机环境部署方案《VirtualBox+OELR5U7x86_64+Oracle11gR2》...
查看>>
值得推荐的C/C++开源框架和库
查看>>
列式存储
查看>>
Linux下eclipse编译C/C++程序遇到 undefined reference to `pthread_create'的异常解决办法
查看>>
ajax上传图片的本质
查看>>
转]最长递增子序列问题的求解
查看>>
SilverLight:基础控件使用(6)-Slider控件
查看>>
Android写的一个设置图片查看器,可以调整透明度
查看>>
第 5 章 File Share
查看>>
判断字符串解析是JsonObject或者JsonArray
查看>>
[LeetCode] Implement strStr()
查看>>
多模块Struts应用程序的几个问题(及部分解决方法)
查看>>
1.2. MariaDB
查看>>
SpringSide示例之HelloWorld
查看>>