图解Dijkstra算法过程(java代码实现)

weblog 4801 0 0

前言

 之前的博客中提到了floyd最短路径算法,此算法的优点是,简单易懂,核心算法代码只有5行,但是缺点是时间复杂度o(n3),时间复杂度太高。而下面要介绍的Dijkstra算法虽然设计上略有复杂,但是时间复杂度确能降低到o(n2)。

百科

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

问题案例

还以之前提到的那个路径问题为例,连图也是复制过来的。

Dijkstra的算法思路

1.把所有的节点分为两个集合分别是S集合(探索过程中已知的最短路径的节点的集合),U集合(暂未探索的节点的结合,但是每个节点到达开始节点的距离是可知的,并且是随着探索的过程,到达开始节点的距离是可以不断变化的)。

2.每次探索从U集合中取出距离开始节点最近的那个节点。并将该节点加入S集合,然后更新与该节点相邻的U集合中的各个节点与开始节点的距离(

具体的更新过程是:

如果从开始节点到该节点的距离+从该节点到该节点的相邻节点的距离>开始节点到邻节点的距离,那么就更新开始节点到邻节点的距离

例:开始节点到该节点的距离为a,从该节点到该节点的相邻节点的距离为b, 从开始节点到该节点的相邻节点的距离为c,那么if(a+b>c){c=a+b}

)。

3.如果还没有探索到目标节点,那就一直执行探索过程2,直到达到目标节点结束。
呕心沥血的总结~

伪算法

S=[];
U=[];
While(不是目标节点){
	K=从U集合中找出距离开始节点最近的节点。
	将k节点加入S集合并标记已探索该节点K
	//遍历U集合中所有的该节点的邻节点。
	For(i=0;i<a;i++){
		If(r[k][i]+r[start][k])<=r[start][i]){
			//更新权值
	        r[start][i]=r[k][i]+r[start][k];
        }
    }	
}

最后r[start][end]的值就是最短路径的距离。至于探索过程中经过的路径是什么~后边再说~

以上图为例,分解一下算法执行的过程

从节点1到节点4为例,从图中可以直接看出,从节点1直接到节点4距离为6,而从节点1经过节点2,再经过节点5到节点4的距离5。显然选择第二中方案更好。那么怎么做呢?

第一步先将开始节点1加入S集合

此时:S集合【1(0)  】    U集合【2(1)  3(8)  4(6)  5(∞)  】

第二步选择U集合中距离最小的节点2,加入S集合,并更新U集合中的距离。

此时:S集合【1(0)  2(1)  】        U集合【3(8)  4(6)  5(3)  】

第三步选择U集合中距离最小的节点5,加入S集合,并更新U集合中的距离。

此时:S集合【1(0)  2(1)  5(3)  】        U集合【3(6)  4(5)  】

第三步选择U集合中距离最小的节点4,加入S集合,并更新U集合中的距离。

此时:S集合【1(0)  2(1)  4(5)  5(3)  】    U集合【3(6)  】

这时已经遍历到目标节点4,所以从1节点到4的最短路径为5。

经过的路径为:[1, 2, 5, 4]

算法实现

算法中实现了求从开始节点到目标节点经过的路径,用一个数组parent保存经过该节点时的父节点。到达目标节点后可以用栈的结构反向推算出算法经过的路径。

package com.dzqc.yx;

import java.util.LinkedList;

/**
 * Dijkstra算法
 * @author jiajia
 */
public class Dijkstra {
	/**
	 * 	m 代表正无穷(两个节点之间无法直接到达)
	 */
	public static final int m=Integer.MAX_VALUE>>3;
	/**
	 *	邻接矩阵描述图
	 */
	public static final int r[][]=new int[][]{
		{0,0,0,0,0,0},
		{0,0,1,8,6,m},
		{0,m,0,m,m,2},
		{0,4,m,0,3,8},
		{0,1,m,15,0,10},
		{0,m,m,3,2,0}
	};
	/**
	 *	最短路径节点集合
	 */
	public static final int s[]=new int[r.length];
	/**
	 * 	父节点位置
	 */
	public static final int parent[]=new int[]{-1,-1,-1,-1,-1,-1};
	
	public static void main(String[] args) {
		int start=1;
		int end=4;
		dijkstra(start,end);
		for(int i=1;i<parent.length;i++) {
			System.out.print(i+":"+parent[i]+"\t");
		}
		System.out.println();
		System.out.println("经过路径:"+role(start,end));
	}
	
	public static LinkedList<Integer> role(int start,int end) {
		LinkedList<Integer> stack=new LinkedList<Integer>();
		stack.add(end);
		while(parent[end]!=-1) {
			stack.addFirst(parent[end]);
			end=parent[end];
		}
		stack.addFirst(start);
		return stack;
	}
	
	/**
	 * 	核心算法
	 * @param start
	 * @param end
	 */
	public static void dijkstra(int start,int end){
		/**
		 * 	第一个顶点放入s集合
		 */
		s[start]=1;
		prinf(start);
		int k = start;
		while(s[end]!=1) {
			/**
			 * 	从u集合中选取一个权值最小的节点k
			 */
			int min=m;
			for(int i=1;i<r.length;i++) {
				if(s[i]!=1&&r[start][i]<min) {
					min=r[start][i];
					k=i;
				}
			}
			s[k]=1;
			System.out.println("选择的点为:"+k);
			/**
			 * 	修改节点的权值
			 */
			for(int i=1;i<r.length;i++) {
				if(s[i]!=1&&(r[k][i]+r[start][k])<=r[start][i]) {
					r[start][i]=r[k][i]+r[start][k];
					parent[i]=k;
				}
			}
			prinf(start);
		}
		System.out.println();
		System.out.println("最短路:"+r[start][end]);
	}
	
	/**
	 * 	打印S集合和U集合
	 * @param start
	 */
	public static void prinf(int start) {
		System.out.println();
		System.out.print("S集合【");
		for(int i=1;i<r.length;i++) {
			if(s[i]!=0) {
				System.out.print(i+"("+r[start][i]+")  ");
			}
		}
		System.out.print("】\nU集合【");
		for(int i=1;i<r.length;i++) {
			if(s[i]!=1) {
				System.out.print(i+"("+r[start][i]+")  ");
			}
		}
		System.out.print("】");
	}
}

 


猜你喜欢
java基础 1478 java并发编-理CAS1.什么是cas?CAS:CompareandSwap,即比较再交换。jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS
html图片懒加载 1291 纯js片懒加载lazyLoading.html测试页面
数据结构与算法 2346 广度优先搜索(dfs、深搜)java-数据结构和用邻接矩阵表示的定点之间的关系如下的数据结构:则用邻接矩阵表示为: privatestaticintmap[][]={ {0,3,6
weblog 5797 种在形平面上,有多个节点的路径,求出最低通成本的。常用于游戏中的NPC的移动计,或线上游戏的BOT的移动计上。该Dijkstra一样,可以找到一条最短路径;也像BFS一样,进行启发
mqtt协议 1267 能表示数据包大小的最大值是256M。  对剩余长度字段的编,可理为128进制的运。如果低位字节满128,则向高位字节进1。那么进位系数就是128。  下面是用一段描述对剩余长度字段的计
数据结构与算法 2544 上一篇:广度优先搜索(bfs、广搜)java-数据结构和用邻接矩阵表示的定点之间的关系如下数据结构则用邻接矩阵表示为: privatestaticintmap
java springboot 1726 涉及知识点:java动态编译,java反射,io流,java文件操作,输入输出重定向,多线与线安全,mysql数据库设计等,理起来难度较高。下面是我自己设计的几个问题,和一些测试数据。排序问题
official 935 互斥的软件单标志,双标志先检查、双标志后检查、Peterson学习提示:理各个的思想、原理结合上小节学习的“互斥的四个逻辑部分”,重点理在进入区、退出区都做了什么
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。