Ⅰ. Dijkstra算法介绍
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
特性:
- Dijkstra算法采用了BFS的策略,即一圈一圈向外访问
- Dijkstra算法是种贪心算法
- Dijkstra算法不能处理带负权边的图
- Dijkstra算法只能解决单源最短路径问题(即某一顶点到其他任一顶点的最短路径)
Ⅱ. 原理介绍
Ⅲ. 代码实现
以邻接矩阵方式进行演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <stdio.h>
#define MAX_VERtEX_NUM 20 //顶点的最大个数
#define VRType int //表示弧的权值的类型
#define VertexType int //图中顶点的数据类型
#define INFINITY 65535
typedef struct {
VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据
VRType arcs[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //二维数组,记录顶点之间的关系
int vexnum,arcnum; //记录图的顶点数和弧(边)数
}MGraph;
typedef int PathMatrix[MAX_VERtEX_NUM]; //用于存储最短路径中经过的顶点的下标
typedef int ShortPathTable[MAX_VERtEX_NUM]; //用于存储各个最短路径的权值和
//根据顶点本身数据,判断出顶点在二维数组中的位置,如果顶点是从0开始并且是连续的则不需要这一步
int LocateVex(MGraph * G,VertexType v){
//遍历一维数组,找到变量v
for (int i=0; i<G->vexnum; i++) {
if (G->vexs[i]==v) {
break;
}
}
//如果找不到,输出提示语句,返回-1
if (i>G->vexnum) {
printf("no such vertex.\n");
return -1;
}
return i;
}
//构造有向网
void CreateUDG(MGraph *G){
scanf("%d,%d",&(G->vexnum),&(G->arcnum));
for (int i=0; i<G->vexnum; i++) {
scanf("%d",&(G->vexs[i]));
}
for (int i=0; i<G->vexnum; i++) {
for (int j=0; j<G->vexnum; j++) {
G->arcs[i][j]=INFINITY;
}
}
for (int i=0; i<G->arcnum; i++) {
int v1,v2,w;
scanf("%d,%d,%d",&v1,&v2,&w);
//如果顶点是从0开始并且是连续的则不需要以下几步,直接赋值即可
int n=LocateVex(G, v1);
int m=LocateVex(G, v2);
if (m==-1 ||n==-1) {
printf("no this vertex\n");
return;
}
G->arcs[n][m]=w;
}
}
//下面写法用指针去表示显得有些怪异,可以使用&(cpp),或者typedef指针为一个新的变量
//迪杰斯特拉算法,v0表示有向网中起始点所在数组中的下标
void ShortestPath_Dijkstra(MGraph G,int v0,PathMatrix *p,ShortPathTable *D){
int final[MAX_VERtEX_NUM];//用于存储各顶点是否已经确定最短路径的数组
//对各数组进行初始化
for (int v=0; v<G.vexnum; v++) {
final[v]=0;
(*D)[v]=G.arcs[v0][v];
(*p)[v]=0;
}
//由于以v0位下标的顶点为起始点,所以不用再判断
(*D)[v0]=0;
final[v0]=1;
int k = 0;
for (int i=0; i<G.vexnum; i++) {
int min=INFINITY;
//选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
for (int w=0; w<G.vexnum; w++) {
if (!final[w]) {
if ((*D)[w]<min) {
k=w;
min=(*D)[w];
}
}
}
//设置该顶点的标志位为1,避免下次重复判断
final[k]=1;
//对v0到各顶点的权值进行更新
for (int w=0; w<G.vexnum; w++) {
if (!final[w]&&(min+G.arcs[k][w]<(*D)[w])) {
(*D)[w]=min+G.arcs[k][w];
(*p)[w]=k;//记录各个最短路径上存在的顶点
}
}
}
}
int main(){
MGraph G;
CreateUDG(&G);
PathMatrix P;
ShortPathTable D;
ShortestPath_Dijkstra(G, 0, &P, &D);
for (int i=1; i<G.vexnum; i++) {
printf("V%d - V%d的最短路径中的顶点有(逆序):",0,i);
printf(" V%d",i);
int j=i;
//由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可得到各个最短路径上的所有顶点
while (P[j]!=0) {
printf(" V%d",P[j]);
j=P[j];
}
printf(" V0\n");
}
printf("源点到各顶点的最短路径长度为:\n");
for (int i=1; i<G.vexnum; i++) {
printf("V%d - V%d : %d \n",G.vexs[0],G.vexs[i],D[i]);
}
return 0;
}