Dijkstra算法

参考:

https://blog.csdn.net/heroacool/article/details/51014824

图:

这里写图片描述

基本思想

  1. 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。

  2. 此外,引进两个集合T和U。T的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。

  3. 初始时,T中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是”起点s到该顶点的路径”。然后,从U中找出路径最短的顶点,并将其加入到T中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到T中;接着,更新U中的顶点和顶点对应的路径。 … 重复该操作,直到遍历完所有顶点。

操作步骤

  1. 初始时,T只包含起点s;U包含除s外的其他顶点,且U中顶点的距离∞。基于邻接图根据s更新U中各个顶点到s的距离;若(s,v)的距离小于(s,k)+(k,v)的距离,即更新s的最优路径;

  2. 从U中选出”距离最短的顶点k”,并将顶点k加入到T中;同时,从U中移除顶点k。

  3. 基于邻接图根据顶点k更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;若(s,v)的距离小于(s,k)+(k,v)的距离,即更新s的最优路径;

  4. 重复步骤(2)和(3),直到遍历完所有顶点。

图解

这里写图片描述

以上图G4为例,来对迪杰斯特拉进行算法演示(以第4个顶点D为起点)。以下B节点中23应为13。

这里写图片描述

初始状态:S是已计算出最短路径的顶点集合,U是未计算除最短路径的顶点的集合!

第1步:将顶点D加入到S中。 
此时,S={D(0)}, U={A(∞),B(∞),C(3),E(4),F(∞),G(∞)}。 注:C(3)表示C到起点D的距离是3。

第2步:将顶点C加入到S中。 
上一步操作之后,U中顶点C到起点D的距离最短;因此,将C加入到S中,同时更新U中顶点的距离。以顶点F为例,之前F到D的距离为∞;但是将C加入到S之后,F到D的距离为9=(F,C)+(C,D)。 
此时,S={D(0),C(3)}, U={A(∞),B(23),E(4),F(9),G(∞)}。

第3步:将顶点E加入到S中。 
上一步操作之后,U中顶点E到起点D的距离最短;因此,将E加入到S中,同时更新U中顶点的距离。还是以顶点F为例,之前F到D的距离为9;但是将E加入到S之后,F到D的距离为6=(F,E)+(E,D)。 
此时,S={D(0),C(3),E(4)}, U={A(∞),B(23),F(6),G(12)}。

第4步:将顶点F加入到S中。 
此时,S={D(0),C(3),E(4),F(6)}, U={A(22),B(13),G(12)}。

第5步:将顶点G加入到S中。 
此时,S={D(0),C(3),E(4),F(6),G(12)}, U={A(22),B(13)}。

第6步:将顶点B加入到S中。 
此时,S={D(0),C(3),E(4),F(6),G(12),B(13)}, U={A(22)}。

第7步:将顶点A加入到S中。 
此时,S={D(0),C(3),E(4),F(6),G(12),B(13),A(22)}。

此时,起点D到各个顶点的最短距离就计算出来了:A(22) B(13) C(3) D(0) E(4) F(6) G(12)。

代码实现(Java)

import java.util.LinkedList;
import java.util.List;

public class Main {
	
	final static int INF = 1000;
	
	public static void main(String[] args) {
		int[][] a = { 	{ INF, 12,  INF, INF, INF,  16, 14  },
		   				{ 12 , INF,  10, INF, INF,   7, INF },
		   				{ INF, 10,  INF,   3,   5,   6, INF },
		   				{ INF, INF,	  3, INF,   4, INF, INF },
		   				{ INF, INF,   5,   4, INF,   2,   8 },
		   				{  16,   7,	  6, INF,   2, INF,   9 },
		   				{  14, INF, INF, INF,   8,	 9,	INF }
		   			};
		
		List<Node> T = new LinkedList<>();//已经成功找到最小点的集合
		List<Node> U = new LinkedList<>();//还没成功找到最小点的集合
		//将起始点加入T
		T.add(new Node(0,0));
		//其他点的初始权重设为无穷大,并相对于七十点根据邻接矩阵进行更新
		for (int i = 1; i < a[0].length; i++) {
			U.add(new Node(INF,i));
		}
		updataU(a,T.get(0),U);//更新路径
		/*核心算法
		 * 1、找到U中目前权重最小的点indexMin
		 * 2、将indexMin从U转入T
		 * 3、更新U中节点的权重
		 */
		for (int i = 1; i < a.length; i++) {
			int indexMin = findMin(U);
			Node nodeTemp = U.get(indexMin);
			//nodeTemp.path.add(0);
			T.add(nodeTemp);
			U.remove(indexMin);
			updataU(a,nodeTemp,U);
		}
		
		//输出
		for (int i = 0; i < T.size(); i++) {
			System.out.print(i+1 +"  "+ T.get(i).weight+"  ");
			System.out.println(path(T.get(i)));
		}
		
	}
	/**
	 * 求node节点的最优路径
	 * @param node
	 * @return 若为起始点,返回0;否则,返回上一节点路径+当前节点
	 */
	private static String path(Node node) {
		if(node.last != null) 
			return path(node.last) +"->"+ node.index;
		else
			return "0";
		
	}
	/**
	 * 基于a根据nodeTemp更新u
	 * @param a 邻接矩阵
	 * @param nodeTemp 新加入的节点
	 * @param u 待更新的U
	 * 如果经由nodeTemp到达当前节点的路径的权重更小,则跟新当前节点权重,并更新当前节点的前置节点
	 */
	private static void updataU(int[][] a, Node nodeTemp, List<Node> u) {
		
		for (int i = 0; i < u.size(); i++) {
			if(a[nodeTemp.index][u.get(i).index]+nodeTemp.weight < u.get(i).weight) {
				u.get(i).weight = a[nodeTemp.index][u.get(i).index]+nodeTemp.weight;
				u.get(i).last = nodeTemp;
			}
		}
	}
	/**
	 * 根据u中元素的路径权重找出权重最小的元素
	 * @param u
	 * @return u中权重最小的元素的索引
	 */
	private static int findMin(List<Node> u) {
		int t = 0;
		for (int i = 1; i < u.size(); i++) {
			if(u.get(i).weight < u.get(t).weight)
				t = i;
		}
		return t;
	}
	
	/**
	 * 节点类
	 * @author alixia
	 * index: 节点索引
	 * weight: 最优路径权重
	 * last: 最优路径上的上一节点
	 */
	private static class Node{
		public int index;
		public int weight;
		public Node last;
		public Node(int weight, int index) {
			this.weight = weight;
			this.index = index;
			this.last = null;
		}
	}
	


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值