当前位置:   article > 正文

最短路径——迪科斯彻算法(Dijkstra)算法_迪斯科算法

迪斯科算法

迪科斯彻算法(Dijkstra)是有荷兰计算机科学家艾兹格·迪科斯彻(Edsger Wybe Dijkstra)发明的。算法解决的是有向图中单个源点到其他顶点的最短路径问题。

算法描述

这个算法是通过为每个顶点 v 保留目前为止所找到的从sv的最短路径来工作的。初始时,原点 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. typedef int VertexType;
  3. typedef int EdgeType;
  4. #define MAXVEX 100
  5. #define INFI 65535
  6. typedef struct
  7. {
  8. VertexType vexs[MAXVEX]; /*顶点表*/
  9. EdgeType matrix[MAXVEX][MAXVEX]; /*邻接矩阵*/
  10. int numVertexes; /*顶点数*/
  11. int numEdges; /*边数*/
  12. }Graph;
  13. /*创建一个邻接矩阵有向图*/
  14. Graph* CreateDiGraph()
  15. {
  16. Graph *pGragh = new Graph;
  17. if (NULL == pGragh)
  18. return NULL;
  19. cout << "输入顶点数和边数:" << endl;
  20. cin >> pGragh->numVertexes >> pGragh->numEdges;
  21. for (int i = 0; i < pGragh->numVertexes; ++i)/*建立顶点表*/
  22. (pGragh->vexs)[i] = i;
  23. for (int i = 0; i < pGragh->numVertexes; ++i)/*邻接矩阵初始化*/
  24. {
  25. for (int j = 0; j < pGragh->numVertexes; ++j)
  26. {
  27. (pGragh->matrix)[i][j] = INFI;
  28. if (i == j)
  29. (pGragh->matrix)[i][j] = 0;
  30. }
  31. }
  32. for (int k = 0; k < pGragh->numEdges; ++k)
  33. {
  34. int i, j, w;
  35. cout << "输入边<vi,vj>上的下标i,下标j和权重w:" << endl;
  36. cin >> i >> j >> w;
  37. (pGragh->matrix)[i][j] = w;//清楚上面输入的顺序,有向边的开始点和终点
  38. }
  39. return pGragh;
  40. }
  41. /*图的邻接矩阵存储方式Dijkstra算法实现
  42. 该算法的目的是:找到图中给定起始点到其余顶点的最短距离*/
  43. /*传参:dist为图pGraph中的起始顶点start到图中各个顶点的最短距离
  44. dist为与图顶点数等值大小的数组,作为返回值
  45. 参数有效性有调用者保证*/
  46. void Dijkstra(Graph *pGraph, int dist[], int start)
  47. {
  48. bool *visited = new bool[pGraph->numVertexes]();//建立踪迹表
  49. visited[start] = true;//记录已经访问的顶点
  50. for (int i = 0; i < pGraph->numVertexes; ++i)
  51. {
  52. dist[i] = (pGraph->matrix)[start][i];//记录起始点start到各顶点的距离
  53. }
  54. int index;
  55. for (int i = 1; i < pGraph->numVertexes; ++i)
  56. {
  57. int mincost = INFI;
  58. for (int j = 0; j < pGraph->numVertexes; ++j)
  59. {
  60. if (!visited[j] && dist[j] < mincost)//选出起始点到其余顶点中的最小距离的那个顶点
  61. {
  62. mincost = dist[j];
  63. index = j;//记录该最小距离顶点
  64. }
  65. }
  66. visited[index] = true;//标记为已经访问过
  67. for (int j = 0; j < pGraph->numVertexes; ++j)
  68. {
  69. /*d[u] + w(u,v) < d[v] 就更新为最小距离为d[u]+w(u,v)*/
  70. if (!visited[j] && (dist[index] + (pGraph->matrix)[index][j]) < dist[j])
  71. dist[j] = dist[index] + (pGraph->matrix)[index][j];
  72. //dist 中保存的始终都是起始顶点start到图其余各顶点间的距离(访问过的就更新为最小)
  73. }
  74. }
  75. }
需要注意的是,上面的Dijkstra算法得到的只是起始点到各个顶点的最小距离值,并没有记录其到达的最短路径。如果要计算某两个顶点之间的最短路径的话,可在更新最小距离的时候把中间顶点保存即可。实现比较简单就不贴出来了。

二、邻接表实现
相信经过了上面,举一反三的你也会很容易把邻接表的Dijkstra 算法实现出来。(懒啊,图片来源于《大话数据结构》,向作者致敬)

 

  1. typedef int VertexType;
  2. typedef int EdgeType;
  3. #define INFI 65535
  4. /*下面构成一个链式哈希表结构*/
  5. /*边表结点*/
  6. typedef struct AdjNode
  7. {
  8. int adjvex; //边的终点
  9. int weight; //边的权重
  10. struct AdjNode *next; //指向下一个邻接点
  11. }AdjNode;
  12. /*顶点表结点*/
  13. typedef struct VertexNode
  14. {
  15. VertexType data; //顶点信息
  16. AdjNode *pFfirstedge; //边表头指针
  17. }VertexNode;
  18. /*图结点*/
  19. typedef struct Graph
  20. {
  21. VertexNode *AdjArray; //指向顶点表
  22. int numVertexes;
  23. int numEdges;
  24. }Graph;
  25. Graph* CreateDiGraph()
  26. {
  27. Graph *pGraph = new Graph;
  28. AdjNode *pNode = NULL;
  29. if (NULL == pGraph)
  30. return NULL;
  31. cout << "输入顶点数和边数:" << endl;
  32. cin >> pGraph->numVertexes >> pGraph->numEdges;
  33. pGraph->AdjArray = new VertexNode[pGraph->numVertexes]();//创建并初始化为0
  34. if (NULL == pGraph->AdjArray)
  35. {
  36. delete pGraph;
  37. return NULL;
  38. }
  39. /*建立顶点信息表*/
  40. for (int i = 0; i < pGraph->numVertexes; ++i)
  41. {
  42. /*这里默认顶点从0到pGraph->numVertexes,可根据需要修改
  43. 如:
  44. cout << "输入顶点信息" << endl;
  45. cin >> (pGraph->AdjArray)[i].data;
  46. */
  47. (pGraph->AdjArray)[i].data = i;
  48. }
  49. /*建立边表*/
  50. for (int k = 0; k < pGraph->numEdges; ++k)
  51. {
  52. int i, j, w;
  53. cout << "输入边<vi,vj>上的下标i,下标j和权重w:" << endl;
  54. cin >> i >> j >> w;
  55. pNode = new AdjNode;
  56. if (NULL == pNode)
  57. {
  58. delete[] pGraph->AdjArray;
  59. delete pGraph;
  60. return NULL;
  61. }
  62. pNode->adjvex = j;
  63. pNode->weight = w;
  64. pNode->next = (pGraph->AdjArray)[i].pFfirstedge;//类链式哈希表插入操作,新节点插入到链表头结点
  65. (pGraph->AdjArray)[i].pFfirstedge = pNode;
  66. }
  67. return pGraph;
  68. }
  69. /*这里着重阐述算法实现,参数的有效性由调用者保证*/
  70. /*dist中保存的则是起始点start到图中各顶点的最小距离*/
  71. void Dijkstra(Graph *pGraph,int dist[], int start)
  72. {
  73. bool *visited = new bool[pGraph->numVertexes]();
  74. visited[start] = true;
  75. /*不同于邻接矩阵,注意这里的初始化距离*/
  76. for (int i = 0; i < pGraph->numVertexes; ++i)
  77. dist[i] = INFI;
  78. dist[start] = 0;
  79. /*记录起始点到各邻接点的距离*/
  80. for (AdjNode *ptmp = (pGraph->AdjArray)[start].pFfirstedge; ptmp; ptmp = ptmp->next)
  81. {
  82. dist[ptmp->adjvex] = ptmp->weight;
  83. }
  84. int index;
  85. for (int i = 1; i < pGraph->numVertexes; ++i)
  86. {
  87. int mincost = INFI;
  88. /*选择其中最小的距离的顶点*/
  89. for (int j = 0; j < pGraph->numVertexes; ++j)
  90. {
  91. if (!visited[j] && dist[j] < mincost)
  92. {
  93. mincost = dist[j];
  94. index = j;
  95. }
  96. }
  97. /*以该顶点x为中间点,找到下一个点y,如果起始点start到中间点x的距离加上x到y的距离小于start到y的距离,则更新*/
  98. /*换言之,如果直接从北京到深圳用的钱比从先从北京到上海,再从上海转机到深圳要多,那么就选择后面这个方案*/
  99. visited[index] = true;
  100. for (AdjNode *ptmp = (pGraph->AdjArray)[index].pFfirstedge; ptmp; ptmp = ptmp->next)
  101. {
  102. if (!visited[ptmp->adjvex] && (dist[index] + ptmp->weight) < dist[ptmp->adjvex])
  103. dist[ptmp->adjvex] = dist[index] + ptmp->weight;
  104. }
  105. }
  106. }
可以看出迪科斯彻算法的时间复杂度为O(n^2),对于邻接矩阵空间复杂度为O(n^2)。

图的邻接表存储实现: http://blog.csdn.net/wenqian1991/article/details/24667287

图的邻接矩阵存储实现:http://blog.csdn.net/wenqian1991/article/details/47123807

图的DFS和BFS:     http://blog.csdn.net/wenqian1991/article/details/24812393







声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/128040
推荐阅读
相关标签
  

闽ICP备14008679号