dikstra与floyd算法求有向图最短路径

求有向图中两节点最短路径时应该很经典的问题,常用的算法有dikstra算法和floyd算法,今天我们就来研究这两种算法,我
把两种算法封装为一个工具类,便于调用,如下。

package com.ityang.solve;

import java.util.ArrayList;
import java.util.List;

public class ShortestPathUtils {
	/**
	 * 封装路径信息的类
	 * @author Administrator
	 *
	 */
	public static class Path {
		public int lengh; //路径长度
		public List<Integer> pathBackup; //路径所经过的所有点
	}
	
	/**
	 * 
	 * @param source 起始点下标
	 * @param dest	   终点下标
	 * @param num    图中节点个数
	 * @param costs  图的邻接矩阵(两节点间无路径相连,用Integer.MAX_VALUE/2表示
	 * @return 路径 无路径时返回空
	 */
	public static Path dikstraShortestSinglePath(int source, int dest, int num,
			int[][] costs) {

		int[] d = new int[num];
		//标示source到其它节点是否已经求出最短路径
		boolean[] isShort = new boolean[num];
		//路径还原时用,存放路径中上一个节点下标
		int[] pre = new int[num];
		//初始化
		for (int i = 0; i < num; i++) {
			isShort[i] = false;
		}
		for (int i = 0; i < num; i++) {
			pre[i] = -1;
		}
		//dikstra算法求最短路径
		dikstra(source, num, isShort, pre, costs, d);
		if (d[dest] == Integer.MAX_VALUE/2) {
			return null;
		}
		Path path = new Path();

		path.lengh = d[dest];
		//还原路径
		List<Integer> pathBackup = new ArrayList<>();
		pathBackup.add(dest);
		for (int i = dest; pre[i] != -1;) {
			pathBackup.add(i = pre[i]);
		}
		pathBackup.add(source);
		path.pathBackup = pathBackup;

		return path;
	}
	/**
	 * 
	 * @param s
	 * @param num
	 * @param isShort
	 * @param pre
	 * @param costs
	 * @param d
	 */
	private static void dikstra(int s, int num, boolean[] isShort, int[] pre,
			int[][] costs, int[] d) {
		fill(s, num, costs, d);
		while (true) {
			int i = getMinIndex(isShort, num, d);
			if (i == -1) {
				break;
			}
			//i号节点已求出到source节点的最短路径
			isShort[i] = true;
			for (int j = 0; j < num; j++) {
				if (!isShort[j] && (d[j] > d[i] + costs[i][j])) {
					d[j] = d[i] + costs[i][j];
					//存放上一节点下标
					pre[j] = i;
				}
			}
		}
	}
	/**
	 * 在未求出最短路径的所有节点中选出路径最小值
	 * @param isShort
	 * @param num
	 * @param d
	 * @return
	 */
	private static int getMinIndex(boolean[] isShort, int num, int[] d) {
		int i = -1;
		for (int u = 0; u < num; u++) {
			if (!isShort[u] && (i == -1 || d[u] < d[i]))
				i = u;
		}
		return i;
	}
	/**
	 * 路径长度初始化
	 * @param s
	 * @param num
	 * @param costs
	 * @param d
	 */
	private static void fill(int s, int num, int[][] costs, int[] d) {
		for (int i = 0; i < num; i++) {
			d[i] = costs[s][i];
		}
	}
	
	/**
	 * 
	 * @param source
	 * @param dest
	 * @param num
	 * @param costs
	 * @return
	 */
	public static Path floydShortestSinglePath(int source, int dest, int num,
			int[][] costs) {
		int[][] mid = new int[num][num];
		for (int i = 0; i < num; i++) {
			for (int j = 0; j < num; j++) {
				mid[i][j] = -1;
			}
		}
		for (int k = 0; k < num; k++) {
			for (int i = 0; i < num; i++) {
				for (int j = 0; j < num; j++) {
					if (costs[i][j] > costs[i][k] + costs[k][j]){
						costs[i][j] = costs[i][k] + costs[k][j];
						mid[i][j]=k;
					}
				}
			}
		}
		
		if (costs[source][dest] == Integer.MAX_VALUE/2 )
			return null;
		
		Path path = new Path();

		path.lengh = costs[source][dest];

		List<Integer> pathBackup = new ArrayList<>();
		pathBackup.add(source);
		
		while(mid[source][dest]!=-1){
			pathBackup.add(mid[source][dest]);
			source = mid[source][dest];
		}
		
		pathBackup.add(dest);
		path.pathBackup = pathBackup;

		return path;

	}
}

现在看调用工具类计算最短路径

package com.ityang.solve;

import com.ityang.solve.ShortestPathUtils.Path;

public class GraphShortest {

	
	private static int[][] costs = {
			{ 0, 2, Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, 3, 1 },
			{ Integer.MAX_VALUE / 2, 0, 2, Integer.MAX_VALUE / 2,
					Integer.MAX_VALUE / 2, 2 },
			{ Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, 0, 1,
					Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2 },
			{ Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2,
					Integer.MAX_VALUE / 2, 0, 4, 6 },
			{ Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2,
					Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, 0,
					Integer.MAX_VALUE / 2 },
			{ 3, Integer.MAX_VALUE / 2, 4, 3, 1, 0 } };

	public static void main(String[] args) {
		Path path1 = ShortestPathUtils.dikstraShortestSinglePath(0, 3, 6, costs);
		Path path2 = ShortestPathUtils.floydShortestSinglePath(0, 3, 6, costs);
		if(path1!=null){
			System.out.println("路径长度:"+path1.lengh);
			System.out.println("路径如下");
			for (int i=path1.pathBackup.size()-1;i>=0;i--) {
				System.out.print(path1.pathBackup.get(i)+"  ");
			}
		}
		if(path2!=null){
			System.out.println("路径长度:"+path2.lengh);
			System.out.println("路径如下");
			for (int i=0;i<path2.pathBackup.size();i++) {
				System.out.print(path2.pathBackup.get(i)+"  ");
			}
		}
	}


}

控制台输出结果

dikstra算法计算路径长度:4

路径如下

0  5  3  

floyd算法计算路径长度:4

路径如下

0  5  3  

后面我有输出了运行时间,来看看两种算法的效率吧

dikstra开始:1458285239203

dikstra结束:1458285239203

floyd开始1458285239203

floyd结束1458285239203

由于我这里只有6个节点,所以看不出什么差距,用时都接近为0,大家可以试试更多的节点,更复杂的路径,哪有就能看出两种算法的差别了。








转载于:https://my.oschina.net/u/2434774/blog/639967

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值