原文地址:http://blog.csdn.net/stanfordzhang/article/details/6626584
1. Dijkstra's Algorithm是解决单源最短路径问题,即:从某个源点到其余各顶点的最短路径;
2. Dijkstra's Algorithm中有两上关键点要注意(这是我学习的时候不仔细,导致走了很多弯路)。这里先明确两个集合:所有顶点集V和已选中顶点集S。
一、找到当前未选中点(V - S)中距离源点最近的点;
二、更新未选中点到源点的距离。
3. 建议:结合程序及一个示例来理解这个算法。我在学习时,看别人画的各种表格来描述这个算法,看了半天,感觉是明白了,但常常发现有不明确的地方。在结合程序理解算法之后,则有豁然开朗之感。
下图来自《Introduction of Algorithm》中的示例,这个示例个人觉得很典型,如下图:
程序如下(来自《数据结构(C语言版)》——严蔚敏):
- void ShortestPath_Dijkstra(size_t** arcs, size_t v0, bool** P, size_t* D, size_t vexnum)
- {
- size_t i = 0;
- size_t v = 0;
- size_t w = 0;
- size_t min = 0;
- //用Dijkstra算法求有向网的v0顶点到其余顶点v的最短路径P[v]及其带权长度D[v]。
- //P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点。
- //final[v]为true,当且仅当v属于S时,即已经求得从v0到v的最短路径。
- bool* final = new bool[vexnum];
- for (v = 0; v < vexnum; v++)
- {
- //初始化
- final[v] = false;
- D[v] = arcs[v0][v];
- for (w = 0; w <vexnum; w++)
- {
- P[v][w] = false; // 设置空路径
- }
- //P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点。
- //在这里初始化,说明v0到v的路径上可通,则v0和v点都在最短路径的点上。
- if (D[v] < INFINITY)
- {
- P[v][v0] = true;
- P[v][v] = true;
- }
- }
- //初始化,v0顶点属于S集
- D[v0] = 0;
- final[v0] = true;
- //开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集
- for (i = 1; i < vexnum; i++) // 其余vexnum - 1个点
- {
- min = INFINITY; // 当前所知离v0顶点的最近距离
- //注意:这个循环用来找到距离v0最近的点
- for (w = 0; w < vexnum; w++)
- {
- if (!final[w]) // w顶点在V - S中
- {
- //w顶点离v0顶点更近
- if (D[w] < min)
- {
- v = w;
- min = D[w];
- }
- }
- }
- //找到之后,将v放入S中
- final[v] = true;
- //更新当前最短路径及距离
- for (w = 0; w < vexnum; w++)
- {
- //修改D[w]和P[w],w属于V - S
- //当前找到的点是v,更新v到V - S中的点的距离,因为有时D[w]中的距离不是直连的
- if (!final[w] && (min + arcs[v][w] < D[w]))
- {
- D[w] = min + arcs[v][w];
- //P[w] = P[v];
- //P为一个二维矩阵,每一行代表到这一行所代表结点的最短路径,行标代表结点下标。
- //因为P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点,此时v是当前找到的点,
- //将P[v]复制到P[w]中,并且将P[w][w]设置为true,也就是在点v的基础上加点w。
- memcpy(P[w], P[v], vexnum);
- P[w][w] = true;
- }
- }
- }
- }
public class Dijkstra { public static void main(String[] args) { new Dijkstra().use(); } public void use(){ new Dijkstra().dijkstra(0, a, dist, prev); for (int i = 0; i < dist.length; i++) { System.out.print(dist[i]+" "); } } //单元最短路径问题的Dijkstra算法 public void dijkstra(int v ,float[][] a, float[] dist,int[] prev){ int n = dist.length - 1 ; if(v < 0 || v > n-1) return; boolean[] s = new boolean[n+1]; //初始化 for(int i = 1; i <= n; i++){ dist[i] = a[v][i]; s[i] = false; if(dist[i] == Float.MAX_VALUE){ prev[i] = 0; } else { prev[i] = v; } } dist[v] = 0; s[v] = true; for(int i = 1; i < n; i++){ float temp = Float.MAX_VALUE; int u = v; for(int j = 1; j <= n; j++){ if((!s[j]) && (dist[j] < temp)){ u = j; temp = dist[j]; } } s[u] = true; //找到了第一个并入S的节点 for(int j = 1; j <= n; j++){ if((!s[j]) && (a[u][j] < Float.MAX_VALUE)){ float newdist = dist[u] + a[u][j]; if(newdist < dist[j]){ //dist[j] 减少 dist[j] = newdist; prev[j] = u; } } } } } private float[][] a = { {0,10,max,30,100}, {max,0,50,max,max}, {max,max,0,max,10}, {max,max,20,0,60}, {max,max,max,max,0} }; private float[] dist = new float[5]; private int[] prev = new int[5]; public static final float max = Float.MAX_VALUE; } |