迪科斯彻算法(Dijkstra)是有荷兰计算机科学家艾兹格·迪科斯彻(Edsger Wybe Dijkstra)发明的。算法解决的是有向图中单个源点到其他顶点的最短路径问题。
算法描述
这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。初始时,原点 s 的路径长度值被赋为 0 (d[s] = 0),同时把所有其他顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于 V 中所有顶点 v 除 s 外d[v] = ∞)。当算法结束时,d[v] 中储存的便是从 s 到 v 的最短路径,或者如果路径不存在的话是无穷大。 Dijkstra 算法的基础操作是边的拓展:如果存在一条从 u 到 v 的边,那么从 s 到 v 的最短路径可以通过将边(u, v)添加到尾部来拓展一条从 s 到 u 的路径。这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小,我们可以用新值来替代当前 d[v] 中的值。拓展边的操作一直执行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。这个算法经过组织因而当 d[u] 达到它最终的值的时候每条边(u, v)都只被拓展一次。
算法维护两个顶点集 S 和 Q。集合 S 保留了我们已知的所有 d[v] 的值已经是最短路径的值顶点,而集合 Q 则保留其他所有顶点。集合S初始状态为空,而后每一步都有一个顶点从 Q 移动到 S。这个被选择的顶点是 Q 中拥有最小的 d[u] 值的顶点。当一个顶点 u 从 Q 中转移到了 S 中,算法对每条外接边 (u, v) 进行拓展。
算法实现 算法实现起来比较简单,当然这得归功于算法作者。
一、邻接矩阵实现
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 typedef int VertexType;typedef int EdgeType;#define MAXVEX 100 #define INFI 65535 typedef struct { VertexType vexs[MAXVEX]; EdgeType matrix[MAXVEX][MAXVEX]; int numVertexes; int numEdges; }Graph; Graph* CreateDiGraph () { Graph *pGragh = new Graph; if (NULL == pGragh) return NULL ; cout << "输入顶点数和边数:" << endl ; cin >> pGragh->numVertexes >> pGragh->numEdges; for (int i = 0 ; i < pGragh->numVertexes; ++i) (pGragh->vexs)[i] = i; for (int i = 0 ; i < pGragh->numVertexes; ++i) { for (int j = 0 ; j < pGragh->numVertexes; ++j) { (pGragh->matrix)[i][j] = INFI; if (i == j) (pGragh->matrix)[i][j] = 0 ; } } for (int k = 0 ; k < pGragh->numEdges; ++k) { int i, j, w; cout << "输入边<vi,vj>上的下标i,下标j和权重w:" << endl ; cin >> i >> j >> w; (pGragh->matrix)[i][j] = w; } return pGragh; }
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 void Dijkstra(Graph *pGraph, int dist[], int start) { bool *visited = new bool [pGraph->numVertexes](); visited[start] = true ; for (int i = 0 ; i < pGraph->numVertexes; ++i) { dist[i] = (pGraph->matrix)[start][i]; } int index; for (int i = 1 ; i < pGraph->numVertexes; ++i) { int mincost = INFI; for (int j = 0 ; j < pGraph->numVertexes; ++j) { if (!visited[j] && dist[j] < mincost) { mincost = dist[j]; index = j; } } visited[index] = true ; for (int j = 0 ; j < pGraph->numVertexes; ++j) { if (!visited[j] && (dist[index] + (pGraph->matrix)[index][j]) < dist[j]) dist[j] = dist[index] + (pGraph->matrix)[index][j]; } } }
需要注意的是,上面的Dijkstra算法得到的只是起始点到各个顶点的最小距离值,并没有记录其到达的最短路径。如果要计算某两个顶点之间的最短路径的话,可在更新最小距离的时候把中间顶点保存即可。实现比较简单就不贴出来了。 二、邻接表实现 相信经过了上面,举一反三的你也会很容易把邻接表的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 typedef int VertexType;typedef int EdgeType;#define INFI 65535 typedef struct AdjNode { int adjvex; int weight; struct AdjNode *next ; }AdjNode; typedef struct VertexNode { VertexType data; AdjNode *pFfirstedge; }VertexNode; typedef struct Graph { VertexNode *AdjArray; int numVertexes; int numEdges; }Graph; Graph* CreateDiGraph () { Graph *pGraph = new Graph; AdjNode *pNode = NULL ; if (NULL == pGraph) return NULL ; cout << "输入顶点数和边数:" << endl ; cin >> pGraph->numVertexes >> pGraph->numEdges; pGraph->AdjArray = new VertexNode[pGraph->numVertexes](); if (NULL == pGraph->AdjArray) { delete pGraph; return NULL ; } for (int i = 0 ; i < pGraph->numVertexes; ++i) { (pGraph->AdjArray)[i].data = i; } for (int k = 0 ; k < pGraph->numEdges; ++k) { int i, j, w; cout << "输入边<vi,vj>上的下标i,下标j和权重w:" << endl ; cin >> i >> j >> w; pNode = new AdjNode; if (NULL == pNode) { delete [] pGraph->AdjArray; delete pGraph; return NULL ; } pNode->adjvex = j; pNode->weight = w; pNode->next = (pGraph->AdjArray)[i].pFfirstedge; (pGraph->AdjArray)[i].pFfirstedge = pNode; } return pGraph; }
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 void Dijkstra(Graph *pGraph,int dist[], int start) { bool *visited = new bool[pGraph-> numVertexes](); visited[start] = true ; for (int i = 0; i < pGraph-> numVertexes; ++i) dist[i] = INFI; dist[start] = 0 ; for (AdjNode *ptmp = (pGraph-> AdjArray )[start].pFfirstedge; ptmp; ptmp = ptmp-> next) { dist [ptmp->adjvex ] = ptmp-> weight; } int index; for (int i = 1; i < pGraph-> numVertexes; ++i) { int mincost = INFI; for (int j = 0; j < pGraph-> numVertexes; ++j) { if (!visited[j] && dist[j] < mincost) { mincost = dist[j]; index = j; } } visited[index] = true ; for (AdjNode *ptmp = (pGraph-> AdjArray )[index].pFfirstedge; ptmp; ptmp = ptmp-> next) { if (!visited[ptmp->adjvex ] && (dist[index] + ptmp->weight ) < dist[ptmp-> adjvex]) dist [ptmp->adjvex ] = dist[index] + ptmp-> weight; } } }
可以看出迪科斯彻算法的时间复杂度为O(n^2),对于邻接矩阵空间复杂度为O(n^2)。