本章介绍迪杰斯特拉算法。和以往一样,本文会先对迪杰斯特拉算法的理论论知识进行介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现。

目录
1. 迪杰斯特拉算法介绍
2. 迪杰斯特拉算法图解
3. 迪杰斯特拉算法的代码说明
4. 迪杰斯特拉算法的源码

转载请注明出处:http://www.cnblogs.com/skywang12345/

更多内容:数据结构与算法系列 目录

迪杰斯特拉算法介绍

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

基本思想

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

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

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

操作步骤

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

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

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

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

单纯的看上面的理论可能比较难以理解,下面通过实例来对该算法进行说明。

迪杰斯特拉算法图解

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

初始状态: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)

迪杰斯特拉算法的代码说明

以"邻接矩阵"为例对迪杰斯特拉算法进行说明,对于"邻接表"实现的图在后面会给出相应的源码。

1. 基本定义

// 邻接矩阵
typedef struct _graph
{
char vexs[MAX]; // 顶点集合
int vexnum; // 顶点数
int edgnum; // 边数
int matrix[MAX][MAX]; // 邻接矩阵
}Graph, *PGraph; // 边的结构体
typedef struct _EdgeData
{
char start; // 边的起点
char end; // 边的终点
int weight; // 边的权重
}EData;

Graph是邻接矩阵对应的结构体。
vexs用于保存顶点,vexnum是顶点数,edgnum是边数;matrix则是用于保存矩阵信息的二维数组。例如,matrix[i][j]=1,则表示"顶点i(即vexs[i])"和"顶点j(即vexs[j])"是邻接点;matrix[i][j]=0,则表示它们不是邻接点。
EData是邻接矩阵边对应的结构体。

2. 迪杰斯特拉算法

/*
* Dijkstra最短路径。
* 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
*
* 参数说明:
* G -- 图
* vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
* prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
* dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
*/
void dijkstra(Graph G, int vs, int prev[], int dist[])
{
int i,j,k;
int min;
int tmp;
int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。 // 初始化
for (i = 0; i < G.vexnum; i++)
{
flag[i] = 0; // 顶点i的最短路径还没获取到。
prev[i] = 0; // 顶点i的前驱顶点为0。
dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。
} // 对"顶点vs"自身进行初始化
flag[vs] = 1;
dist[vs] = 0; // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。
for (i = 1; i < G.vexnum; i++)
{
// 寻找当前最小的路径;
// 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
min = INF;
for (j = 0; j < G.vexnum; j++)
{
if (flag[j]==0 && dist[j]<min)
{
min = dist[j];
k = j;
}
}
// 标记"顶点k"为已经获取到最短路径
flag[k] = 1; // 修正当前最短路径和前驱顶点
// 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
for (j = 0; j < G.vexnum; j++)
{
tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出
if (flag[j] == 0 && (tmp < dist[j]) )
{
dist[j] = tmp;
prev[j] = k;
}
}
} // 打印dijkstra最短路径的结果
printf("dijkstra(%c): \n", G.vexs[vs]);
for (i = 0; i < G.vexnum; i++)
printf(" shortest(%c, %c)=%d\n", G.vexs[vs], G.vexs[i], dist[i]);
}

迪杰斯特拉算法的源码

这里分别给出"邻接矩阵图"和"邻接表图"的迪杰斯特拉算法源码。

1. 邻接矩阵源码(matrix_udg.c)

2. 邻接表源码(list_udg.c)

Dijkstra算法(一)之 C语言详解的更多相关文章

  1. Floyd算法(一)之 C语言详解

    本章介绍弗洛伊德算法.和以往一样,本文会先对弗洛伊德算法的理论论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 弗洛伊德算法介绍 2. 弗洛伊德算法图解 3 ...

  2. Prim算法(一)之 C语言详解

    本章介绍普里姆算法.和以往一样,本文会先对普里姆算法的理论论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 普里姆算法介绍 2. 普里姆算法图解 3. 普里 ...

  3. Kruskal算法(一)之 C语言详解

    本章介绍克鲁斯卡尔算法.和以往一样,本文会先对克鲁斯卡尔算法的理论论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 最小生成树 2. 克鲁斯卡尔算法介绍 3 ...

  4. 原来Github上的README.md文件这么有意思——Markdown语言详解(sublime text2 版本)

    一直想学习 Markdown 语言,想起以前读的一篇 赵凯强 的 博客 <原来Github上的README.md文件这么有意思——Markdown语言详解>,该篇博主 使用的是Mac系统, ...

  5. Java Web----EL(表达式语言)详解

     Java Web中的EL(表达式语言)详解 表达式语言(Expression Language)简称EL,它是JSP2.0中引入的一个新内容.通过EL可以简化在JSP开发中对对象的引用,从而规范页面 ...

  6. 二分算法题目训练(二)——Exams详解

    CodeForces732D——Exams 详解 Exam 题目描述(google翻译) Vasiliy的考试期限将持续n天.他必须通过m门科目的考试.受试者编号为1至m. 大约每天我们都知道当天可以 ...

  7. 最短路径——dijkstra算法代码(c语言)

    最短路径问题 看了王道的视频,感觉云里雾里的,所以写这个博客来加深理解.(希望能在12点以前写完) 一.总体思想 dijkstra算法的主要思想就是基于贪心,找出从v开始的顶点到各个点的最短路径,做法 ...

  8. Kruskal算法 - C语言详解

    最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树.  例如,对于如上图G4所示的连通网可以有多棵权值总 ...

  9. 拓扑排序(一)之 C语言详解

    本章介绍图的拓扑排序.和以往一样,本文会先对拓扑排序的理论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 拓扑排序介绍 2. 拓扑排序的算法图解 3. 拓扑 ...

随机推荐

  1. erlang学习笔记(文件操作)

    参考这里和这里了解到的文件操作的模块有很多:kernel下有:file,stdlib下有:filelib,filename,file_sorter.(具体查看官方文档)

  2. js实现单文件以及多文件下载

    <script type="text/javascript"> /** * Javascript 多文件下载 * @author Barret Lee * @email ...

  3. MySQL数据库“局部”乱码

    问题:“网页显示中午”与“数据库查看中文”总有一个是乱码,或者“网页中总有部分中文乱码” 装了PHPStudy之后,用alter修改过一次数据库的编码方式为utf8!当时的网页的编码显示是正常的,所以 ...

  4. DOM技术实现竞赛题页面

    DOM技术实现竞赛题页面 这一段时间学习了DOM操作和JS开发,我就自己开发一个竞赛题的页面. 一.业务需求 1.目标:做一个一百道选择题的页面 2.功能: 显示题目和选项. 下一题上一题的按钮,到第 ...

  5. Python学习笔记1——Python基础

    一. 数据类型和变量 整数:十六进制用0x前缀和0-9,a-f表示 浮点数:小数,科学计数法:10用e代替:整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(包括除法),浮点数运算则可 ...

  6. SQL入门经典(九) 之自定义函数

    UDF和存储过程很类似,用户自定义函数是一组有序的T-SQL语句,这些语句被预先优化和编译,并且可以作为一个单元来测试调用.UDF和存储过程的主要区别在于结果返回方式,为了能支持更多返回值,UDF比存 ...

  7. SQL SERVER 2012 只能识别20个CPU的问题

    背景 最近在给客户优化时时候发现客户的虚拟机环境分配了32C 但是只能识别20个,物理机64C,64G内存,本来没什么,CPU利用率在40%左右,但是优化后同时增加了 CPU和内存的分配,CPU32增 ...

  8. node(websocket)

    websocket原本是html5下实现长链接的一个特性,当前已被众多浏览器支持. 在websocket协议中,首先通过http交换一次握手,明确将协议升级至websocket.同时建立一个TCP通道 ...

  9. java提高篇(二一)-----ArrayList

    一.ArrayList概述       ArrayList是实现List接口的动态数组,所谓动态就是它的大小是可变的.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List ...

  10. ehcache2拾遗之copyOnRead,copyOnWrite

    问题描述 缓存在提升应用性能,提高访问效率上都是至关重要的一步.ehcache也是广为使用的缓存之一.但是如果将一个可变的对象(如普通的POJO/List/Map等)存入缓存中,会导致怎样潜在的问题. ...