java数据结构和算法⑧——迪杰斯特拉算法(最短路径)

迪杰斯特拉算法

迪杰斯特拉算法同样也是基于贪婪思想来的,这也是一个图论方面计算最短路径的算法

问题描述

如下图所示,求从1到其他每个点的最短路径
在这里插入图片描述

解决流程

  1. 我们定义一个数组,表示1这个点到其他的点的所有最短距离。

开始我就在第1这个点,INF表示无法抵达(距离无穷大)

在这里插入图片描述

  1. 贪心选择

比如我想通过1到其他的点。如果要产生一个中间点就可以到其他的点,那么我找离我最近的那个点走就一定能到最短的路。

那么我们就应该找离1最近的那个点去中转,显然我应该找到3。

那么3加入我们能走的点此时我们已经有1和3两个点,松弛,加进来的这个点我们去判断他能走的路径和之前存的距离相比较。可以看到3到4的距离是50,而1到3的距离是10,那么1到4的距离就是60,这也显然比INF小,自然改变表上1到4的距离,同时记录路径。

其他的点也是同样的操作,如果距离更近就更改,否则就保持原样。

表中红色的点表示已经找过的点
在这里插入图片描述

  1. 重复上面的步骤继续找离最短的点

很显然是找到5这个点,考虑5加进来到4这个点:最开始不加进来5的时候是60,加进来,我们发现5可以到4 距离为20,1到5是30此时30+20=50<60
在这里插入图片描述
接下来继续找离1最近的点,很显然是4,因为我们4通过中转到的,加入4进来。4可以到6这点 距离为10,我们看从1到4的最短距离为50那么 1-6 可以变成50+10=60 < 90所以更新为60。
在这里插入图片描述
接下来加6,6也不存在可抵达的点,所以表中的值也无需更新
在这里插入图片描述

  1. 直到表中的距离都加过时(除INF外),就表示加完了,此时表中的数据就是1到各个点的最短距离。

代码

public class Dijstarl {

	public static void main(String[] args) {
		int n , m , x;		//n表示n个点,m表示m条边。x表示要求最短路径的点
		
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		m = cin.nextInt();
		x = cin.nextInt();
		
		//距离为了方便我就用数组了
		int value[][] = new int[n+1][n+1];		//表示n个点之间的权重  地图用的是邻接表 因为点太多了
		int dis[] = new int[n+1];		//表示存从x点到每个点的最短路径的
		
		//先初始化图。最开始都认为没有可以走的边
		for(int i=1;i<=n; i++) {
			dis[i] = Integer.MAX_VALUE;		//最开始没有最短距离 都是无穷大 也可以用-1表示
			for(int j =1; j<=n ;j++) {
				if(i == j) value[i][j] = 0 ;	//表示是自己
				else value[i][j] = -1;		//表示从i到j最开始是没有路的
			}
		}
		//接下来输入这个图上面的所有边
		for(int i=1;i<=m;i++) {
			int a = cin.nextInt();
			int b = cin.nextInt();
			int weight = cin.nextInt();		//表示 a点到b点的距离为weight
			value[a][b] = weight;
			//在这里的时候就可以计算出要求最短路径的第一个点,因为第一个点进来就是直达就行了
			if(a == x) {		//表示是我们要求的那个点
				dis[b] = weight;
			}
		}
		dijkstra(x, dis, value, n);
	}
	
	public static void dijkstra(int x,int dis[],int value[][],int n) {
		boolean mark[] = new boolean[n+1];		//标记是不是已经加入过了
		for(int i = 1;i<=n;i++) {
			mark[i] = false;		//最开始是没有加的
		}
		dis[x] = 0;
		mark[x] = true;
		while(true) {	//如果每次都有点加进来 不是O(N) Nlogn
			//找离最近的那个点
			int min = Integer.MAX_VALUE;
			int loc = -1;		//存储最小的那个点
			for(int i =1; i<= n;i++) { //O(n)
				if(!mark[i] && dis[i] < min) {
					min = dis[i];
					loc = i;
				}
			}
			if(loc == -1)break;
			mark[loc] = true;
			for(int i = 1; i <= n;i++) {
				if(value[loc][i] != -1) {		//判断我们加进来的这个点能不能到i
					if(dis[loc] + value[loc][i] < dis[i]) {	//通过中转点能不能减少距离
						dis[i] = dis[loc] + value[loc][i];
					}
				}
			}
		}

		System.out.println(x + "点到每个点的最短距离如下所示:");
		for(int i = 1 ; i <= n;i++) {
			if(dis[i] != Integer.MAX_VALUE) {
				System.out.println("到" + i + "点的最短距离为:" +dis[i]);
			}else{
				System.out.println("不能到达" + i);
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值