基本思想

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

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

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

操作步骤

(1) 初始时,S只包含起点vs;U包含除vs外的其他顶点,且U中顶点的距离为"起点vs到该顶点的距离"[例如,U中顶点v的距离为(vs,v)的长度,然后vs和v不相邻,则v的距离为∞]。

(2) 从U中选出"距离最短的顶点k",并将顶点k加入到S中;同时,从U中移除顶点k。

(3) 更新U中各个顶点到起点vs的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(vs,v)的距离可能大于(vs,k)+(k,v)的距离。

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

接下来做一个简单例子求解:

package com.darrenchan.graph;

import java.util.ArrayList;
import java.util.List; public class ShortestPathDijkstra {
/** 邻接矩阵 */
private int[][] matrix;
/** 表示正无穷 */
private int MAX_WEIGHT = Integer.MAX_VALUE;
/** 顶点集合 */
private String[] vertexes; /**
* 创建图
*/
private void createGraph(int index) {
matrix = new int[index][index];
vertexes = new String[index]; int[] v0 = { 0, 1, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
int[] v1 = { 1, 0, 3, 7, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
int[] v2 = { 5, 3, 0, MAX_WEIGHT, 1, 7, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
int[] v3 = { MAX_WEIGHT, 7, MAX_WEIGHT, 0, 2, MAX_WEIGHT, 3, MAX_WEIGHT, MAX_WEIGHT };
int[] v4 = { MAX_WEIGHT, 5, 1, 2, 0, 3, 6, 9, MAX_WEIGHT };
int[] v5 = { MAX_WEIGHT, MAX_WEIGHT, 7, MAX_WEIGHT, 3, 0, MAX_WEIGHT, 5, MAX_WEIGHT };
int[] v6 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 3, 6, MAX_WEIGHT, 0, 2, 7 };
int[] v7 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 9, 5, 2, 0, 4 };
int[] v8 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 7, 4, 0 };
matrix[0] = v0;
matrix[1] = v1;
matrix[2] = v2;
matrix[3] = v3;
matrix[4] = v4;
matrix[5] = v5;
matrix[6] = v6;
matrix[7] = v7;
matrix[8] = v8; vertexes[0] = "v0";
vertexes[1] = "v1";
vertexes[2] = "v2";
vertexes[3] = "v3";
vertexes[4] = "v4";
vertexes[5] = "v5";
vertexes[6] = "v6";
vertexes[7] = "v7";
vertexes[8] = "v8";
} /**
* Dijkstra最短路径。
*
* vs -- 起始顶点(start vertex) 即,统计图中"顶点vs"到其它各个顶点的最短路径。
*/
public void dijkstra(int vs) {
// flag[i]=true表示"顶点vs"到"顶点i"的最短路径已成功获取
boolean[] flag = new boolean[vertexes.length];
// U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离),与 flag配合使用,flag[i] == true 表示U中i顶点已被移除
int[] U = new int[vertexes.length];
// 前驱顶点数组,即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
int[] prev = new int[vertexes.length];
// S的作用是记录已求出最短路径的顶点
String[] S = new String[vertexes.length]; // 步骤一:初始时,S中只有起点vs;U中是除vs之外的顶点,并且U中顶点的路径是"起点vs到该顶点的路径"。
for (int i = 0; i < vertexes.length; i++) {
flag[i] = false; // 顶点i的最短路径还没获取到。
U[i] = matrix[vs][i]; // 顶点i与顶点vs的初始距离为"顶点vs"到"顶点i"的权。也就是邻接矩阵vs行的数据。 prev[i] = 0; //顶点i的前驱顶点为0
} // 将vs从U中“移除”(U与flag配合使用)
flag[vs] = true;
U[vs] = 0;
// 将vs顶点加入S
S[0] = vertexes[vs];
// 步骤一结束 //步骤四:重复步骤二三,直到遍历完所有顶点。
// 遍历vertexes.length-1次;每次找出一个顶点的最短路径。
int k = 0;
for (int i = 1; i < vertexes.length; i++) {
// 步骤二:从U中找出路径最短的顶点,并将其加入到S中(如果vs顶点到x顶点还有更短的路径的话,那么
// 必然会有一个y顶点到vs顶点的路径比前者更短且没有加入S中
// 所以,U中路径最短顶点的路径就是该顶点的最短路径)
// 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
int min = MAX_WEIGHT;
for (int j = 0; j < vertexes.length; j++) {
if (flag[j] == false && U[j] < min) {
min = U[j];
k = j;
}
} //将k放入S中
S[i] = vertexes[k]; //步骤二结束 //步骤三:更新U中的顶点和顶点对应的路径
//标记"顶点k"为已经获取到最短路径(更新U中的顶点,即将k顶点对应的flag标记为true)
flag[k] = true; //修正当前最短路径和前驱顶点(更新U中剩余顶点对应的路径)
//即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
for (int j = 0; j < vertexes.length; j++) {
//以k顶点所在位置连线其他顶点,判断其他顶点经过最短路径顶点k到达vs顶点是否小于目前的最短路径,是,更新入U,不是,不做处理
int tmp = (matrix[k][j] == MAX_WEIGHT ? MAX_WEIGHT : (min + matrix[k][j]));
if (flag[j] == false && (tmp < U[j])) {
U[j] = tmp;
//更新 j顶点的最短路径前驱顶点为k
prev[j] = k;
}
}
//步骤三结束
}
//步骤四结束 // 打印dijkstra最短路径的结果
System.out.println("起始顶点:" + vertexes[vs]);
for (int i = 0; i < vertexes.length; i++) {
System.out.print("最短路径(" + vertexes[vs] + "," + vertexes[i] + "):" + U[i] + " "); List<String> path = new ArrayList<>();
int j = i;
while (true) {
path.add(vertexes[j]); if (j == 0)
break; j = prev[j];
} for (int x = path.size()-1; x >= 0; x--) {
if (x == 0) {
System.out.println(path.get(x));
} else {
System.out.print(path.get(x) + "->");
}
} } System.out.println("顶点放入S中的顺序:");
for (int i = 0; i< vertexes.length; i++) { System.out.print(S[i]); if (i != vertexes.length-1)
System.out.print("-->");
} } public static void main(String[] args) {
ShortestPathDijkstra dij = new ShortestPathDijkstra();
dij.createGraph(9);
dij.dijkstra(0);
} }

参考:https://blog.csdn.net/CmdSmith/article/details/56839285

[数据结构]迪杰斯特拉(Dijkstra)算法的更多相关文章

  1. 迪杰斯特拉Dijkstra算法介绍

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijk ...

  2. JS实现最短路径之迪杰斯特拉(Dijkstra)算法

    最短路径: 对于网图来说,最短路径是指两个顶点之间经过的边上权值和最少的路径,我们称第一个顶点是源点,最后一个顶点是终点 迪杰斯特拉 ( Dijkstra) 算法是并不是一下子就求出 了 Vo 到V8 ...

  3. 最短路径算法-迪杰斯特拉(Dijkstra)算法在c#中的实现和生产应用

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止 贪心算法(Greedy ...

  4. 最短路径-迪杰斯特拉(dijkstra)算法及优化详解

    简介: dijkstra算法解决图论中源点到任意一点的最短路径. 算法思想: 算法特点: dijkstra算法解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树.该算法常用于路由算 ...

  5. 最短路径 - 迪杰斯特拉(Dijkstra)算法

    对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点为源点,最后一个顶点为终点.最短路径的算法主要有迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd ...

  6. C# 迪杰斯特拉(Dijkstra)算法

    Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 其基本思想是,设置顶点集合S并不断地作 ...

  7. 图的最短路径---迪杰斯特拉(Dijkstra)算法浅析

    什么是最短路径 在网图和非网图中,最短路径的含义是不一样的.对于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径. 对于网图,最短路径就是指两顶点之间经过的边上权值之和最 ...

  8. 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)

    一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...

  9. 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(一)

    一.算法介绍 迪杰斯特拉算法(英语:Dijkstra's algorithm)由荷兰计算机科学家艾兹赫尔·迪杰斯特拉在1956年提出.迪杰斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题. ...

  10. 迪杰斯特拉(Dijkstra)算法

    # include <stdio.h> # define MAX_VERTEXES //最大顶点数 # define INFINITY ;//代表∞ typedef struct {/* ...

随机推荐

  1. javascript的事件机制(百度文库)

    http://wenku.baidu.com/view/9c8761e1524de518964b7d65.html http://wenku.baidu.com/view/1c3d7228bd6478 ...

  2. XGB 调参基本方法

    - xgboost 基本方法和默认参数 - 实战经验中调参方法 - 基于实例具体分析 在训练过程中主要用到两个方法:xgboost.train()和xgboost.cv(). xgboost.trai ...

  3. 解决sklearn 随机森林数据不平衡的方法

    Handle Imbalanced Classes In Random Forest   Preliminaries # Load libraries from sklearn.ensemble im ...

  4. UnicodeDecodeError: 'utf-8' codec can't decode byte

    for line in open('u.item'): #read each line whenever I run this code it gives the following error: U ...

  5. C#基础第九天-作业-储蓄账户(SavingAccount)和信用账户(CreditAccount)

    要求1:完成以下两种账户类型的编码.银行的客户分为两大类:储蓄账户(SavingAccount)和信用账户(CreditAccount),两种的账户类型的区别在于:储蓄账户不允许透支,而信用账户可以透 ...

  6. MySQL -- 内存使用监控详解

    问题: 1.我们怎么确定MySQL的各个部分分别使用了多少内存? 2.当有MySQL由于内存泄露引起OOM时.我们怎么提前发现? 怎么监控MySQL内存使用: 答案是通过performance_sch ...

  7. android sqlite3:数据库操作

    1. 修改表名: alter table notification rename to notification_test 2. 修改数据库名称: 3. 复制一个表的数据到另外一个表中(表的字段一致) ...

  8. php实现文件下载代码一例

    php实现文件下载代码 需要用到header函数来发送相关信息给客户端浏览器,同时再结合filesize函数来读取文件大小并进行下载操作.简单的文件下载只需要使用HTML的连接标记<a>, ...

  9. 【Android】1.1 开发环境安装和配置

    分类:C#.Android.VS2015: 创建日期:2016-01-20 2016-08-03说明:此版本已过时,最新版本见本博客置顶的内容. 一.安装JDK.SDK.NDK 无论是用C#和VS20 ...

  10. sql的split()函数

    ALTER function [dbo].[StrToList_Test](@Str varchar()) returns @table table( value nvarchar(max) ) as ...