Dijkstra算法的深入浅出

一.Dijkstra算法可以解决的问题

在给定的带权有向图中,我们任意指定一个点作为源点,求该源点到其他各点的最短路径时,我们便需要用到Dijkstra算法。

二.Dijkstra算法的实现思想

1.应该用什么数据结构来存储带权有向图?
我们知道,用于存储图的数据结构主要是邻接表和领接矩阵,由于Dijkstra算法需要经常用到边的权值,这里我们采用领接矩阵存储更加好一些。

2.实现Dijkstra算法还需要引入那些数据结构?
(1)in[]t s 用于记录已经走过的点,每当我们找到源点到另一个点的最短路径时,就将该点加入集合s。具体实现时,我们将数组中的所有值初始化为0,每当找到一个点的最短路径,就将该点对应数组的值变为1。
(2)int[] distance 用于记录源点到各个点的最短距离。该数组的值会随着
集合s的更新而更新。
(3)int[] path 用于记录源点到其余各个顶点的关键路径。本质上path[i]记录的是当前结点的上一步骤的点。
(4)全局常量 static int infinite = 10000 表示无穷远。

3.Dijkstra算法的具体实现步骤
(1)根据起始点初始化各个数据结构,包括int[] s,int[] distance,int[] path,起始时由于集合s中只有起始点,所以distance中可能会存在不可达的点,我们将其初始化为“无穷远”。path数组中初始化所有的顶点的上一步为起始点。为了避免在找MIN{distance[i]}时,多次的最小值都是由出发点引出。 其次初始化源点的path值为-1以标志改点为源点。
(2)找出MIN{distance[i]},将其对应的顶点加入集合s。同时更新distance[]数组和s[]数组和path[]数组。
(3)重复(1)(2)两步,直到s[]数组中的值全为-1。

三.java实现Dijkstra算法

eg:如下图求,从顶点v0出发到其余各点的最短路径
在这里插入图片描述

import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;

/*
迪杰斯特拉算法求最短路径
求从某个源点到其余各顶点的最短距离
测试用例:
6 8
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60
*/
public class Dijkstra {
	static int infinite = 10000;           //将此数据定义为无穷远,意味着两顶点不可达
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int numberOfNode = sc.nextInt();   //存储该图的顶点的总数
		int numberOfEdge = sc.nextInt();   //存储该图的边的条数
		
		int[][] tempDate = new int[numberOfEdge][3];       //用于临时存放数据
		int[][] date = new int[numberOfNode][numberOfNode];//领接矩阵来存储该图
		
		for(int i=0;i<numberOfEdge;i++) {
			tempDate[i][0] = sc.nextInt();  //边的始点
			tempDate[i][1] = sc.nextInt();  //边的终点
			tempDate[i][2] = sc.nextInt();  //边的权值
		}
		sc.close();
		
		//稠密数组向稀疏数组转换,即将其转换为领接矩阵存储
		for(int i=0;i<numberOfNode;i++) { //初始化领接矩阵
			for(int j=0;j<numberOfNode;j++) {
				date[i][j] = infinite;
			}
		}
		
		//稠密矩阵向稀疏矩阵转换,将图存储在领接矩阵内
		for(int i=0;i<numberOfEdge;i++) {
			date[tempDate[i][0]][tempDate[i][1]] = tempDate[i][2];
		}
		
		dijkstra(0,date);
	}
	
	//dijkstra算法求最短路径,参数为起始点,和整个领接矩阵
	public static void dijkstra(int start,int[][] graph) {
		int[] s = new int[graph.length];         //集合s
		int[] distance = new int[graph.length];  //用来记录从起始点到其余各点的最短距离
		int[] path = new int[graph.length];      //用来记录从起始点到其余各点的最短路径
		
		//从当前所给起始点出发初始化各数据结构
		for(int i=0;i<graph.length;i++) {
			distance[i] = graph[start][i];
			path[i] = start;
		}
		s[start] = 1;  //将起始点加入集合s
		path[start] = -1;
		int index = minimumIndex(distance,s);
		path[index] = start;
		
		while(index != -1) {
			s[index] = 1;                      //将该元素加入集合s
			for(int i=0;i<graph.length;i++) {  //更新最短距离数组
				if(s[i] != 1 && graph[index][i]+distance[index]<distance[i]) {
					distance[i] = graph[index][i]+distance[index];
					path[i] = index;
				}
			}
			index = minimumIndex(distance,s);
		}
		
		//打印最短路径和最短距离
		for(int i=0;i<distance.length;i++) {
			if(i != start && distance[i] != infinite) {
				System.out.print("起始点"+start+"到点"+i+"的最短距离为:"+distance[i]+"  最短路径为:");
				
				//打印最短路径
				int pro = path[i];
				Stack<Integer> stack = new Stack<>();
				while(pro != -1) {
					stack.push(pro);
					pro = path[pro];
				}
				
				while(!stack.isEmpty()) {
					System.out.print(stack.pop()+"->");
				}
				System.out.println(i);
			}
			
			if(i != start && distance[i] == infinite) {
				System.out.println("起始点"+start+"无法到达点"+i);
			}			
		}
		
	}

	
	//求最短距离所对应的下标
	public static int minimumIndex(int[] distance,int[] s) {
		int count = 0;
		for(int i=0;i<s.length;i++) {
			if(s[i] == 0) {   //只求距离集合s以外的最短距离
				count++;
			}
		}
		
		if(count == 0) { //如果count的值为-1说明所有的顶点都已经加入了集合s,即已经完成的dijkstar算法
			return -1;
		}
		
		int[] minimumToS = new int[count];
		
		int j = 0;
		for(int i=0;i<distance.length;i++) {
			if(s[i] != 1) {
				minimumToS[j++] = distance[i];
			}
		}
		
		Arrays.parallelSort(minimumToS);
		
		for(int i=0;i<distance.length;i++) {
			if(distance[i] == minimumToS[0] && s[i] != 1) {
				return i;
			}
		}
		
		return -1;
	}
}

代码分析:
1.Dijkstra算法的核心在于distance[]数组的更新

s[i] != 1 && graph[index][i]+distance[index]<distance[i]

distance[i]表示当前起始点到顶点i的最短距离,distance[index] + graph[index][i]表示index顶点加入了集合s后和顶点i的距离。

2.如何理解path数组?
在这里插入图片描述
以上即是笔者对Dijkstra算法的简单概述,如有错误还请批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值