当前位置:   article > 正文

C++之最短路径算法(Dijkstra)_c++ 最短路径

c++ 最短路径

 前面我们讲过权值为1时的最短路径的算法,也就是无权最短路径算法。但是如果时赋权图呢?我们该怎么办呢?

解决单源(只有一个开始顶点)最短路径的算法为Dijkstra,而该算法的核心思想是贪婪算法。贪婪算法的思想简单来讲就是“目光短浅,眼前利益为主”,也就是分阶段求解问题,在每个阶段去寻找最优解。Dijkstra算法也是按阶段进行,在每个阶段选择离开始顶点最近的顶点(未访问),我们对每一个顶点(vertex)保留其临时的dis,这个距离是开始顶点v到所访问的顶点的实际的路径长,我们每次要对dis值要进行更新。与无权最短路径算法一样,未访问的顶点的dis为∞。无权最短路径算法每次往前递推加一对dis进行更新。而Dijkastra最短路径算法对新访问的顶点离开始顶点的路径与前一个的顶点的路径加前一个顶点到新访问的顶点的权值进行比较,从而对dis进行更新。让我们看看Dijkstra的核心算法:

  1. void Graph::Dijkstra(size_t v) {
  2. verptr->dis[v] = 0;
  3. while (true) {
  4. size_t min = InFinity; //未访问的顶点到开始顶点的权值为∞
  5. for (int i = 0; i < verptr->vertexnumber; ++i) {
  6. if (verptr->visited[i] == false && min > verptr->dis[i]) { //选择离开始顶点权值最小的顶点
  7. min = verptr->dis[i];
  8. v = i;
  9. }
  10. }
  11. if (min == InFinity) //全部访问完跳出循环
  12. break;
  13. verptr->visited[v] = true; //对访问的进行标记
  14. auto beg = lists[v].begin();
  15. while (beg != lists[v].end()) {
  16. if (verptr->visited[*beg] == false)
  17. if (verptr->dis[v] + weight[v][*beg] < verptr->dis[*beg])
  18. verptr->dis[*beg] = verptr->dis[v] + weight[v][*beg]; //对dis进行更新
  19. ++beg;
  20. }
  21. }
  22. }

 在整个算法过程中查找最小值将的时间复杂度为O(|V|2) (V 为其顶点数),对dis的更新的时间复杂度为O(|E|)(E 为其边数)。因此Dijkstra算法的总的算法时间复杂度为O(|V|2)。那图是稀疏或者稠密时呢?

  • 当为稠密图时(边数大于顶点数),其算法复杂度为E=O(|V|^2){\color{Blue} }

  • 当为稀疏图时(边数小于顶点数),如果dis存储在一维数组中,那么其算法复杂度为E=O(|V|2),这种效率是很低的,因此我们将dis换位优先队列。优先队列的现实我们可以用最小二叉堆(小堆),斐波那契堆,这两种不同的数据结构可以很好的提升算法的性能。

 

 完整源码如下:

  1. #include<iostream>
  2. #include<vector>
  3. #include<list>
  4. #include<memory>
  5. const size_t InFinity = 999;
  6. struct Vertex {
  7. size_t vertexnumber;
  8. bool* visited;
  9. size_t* dis; //储存minweight
  10. };
  11. class Graph {
  12. public:
  13. Graph(const size_t _vertexnumber) :verptr(std::make_unique<Vertex>()), lists(new std::list<size_t>[_vertexnumber]()), weight(std::vector<std::vector<size_t>>(_vertexnumber, std::vector<size_t>(_vertexnumber, -1))) {
  14. verptr->vertexnumber = _vertexnumber;
  15. verptr->visited = new bool[_vertexnumber]();
  16. verptr->dis = new size_t[_vertexnumber]();
  17. for (int i = 0; i < verptr->vertexnumber; ++i)
  18. verptr->dis[i] = InFinity;
  19. }
  20. ~Graph() {
  21. if (verptr->visited && verptr->dis) {
  22. delete[] verptr->visited;
  23. delete[] verptr->dis;
  24. delete[] lists;
  25. }
  26. else
  27. throw std::out_of_range("Out of MemorySpace!!");
  28. }
  29. public:
  30. void AddEdge(const size_t v, const size_t w, const size_t _weight);
  31. void Dijkstra(size_t startv);
  32. void Display(const size_t v)const;
  33. private:
  34. std::unique_ptr<Vertex>verptr;
  35. std::list<size_t>*lists;
  36. std::vector<std::vector<size_t>>weight;
  37. };
  38. void Graph::AddEdge(const size_t v, const size_t w, const size_t _weight) {
  39. lists[v].push_back(w);
  40. weight[v][w] = _weight;
  41. }
  42. void Graph::Dijkstra(size_t v) {
  43. verptr->dis[v] = 0;
  44. while (true) {
  45. size_t min = InFinity;
  46. for (int i = 0; i < verptr->vertexnumber; ++i) {
  47. if (verptr->visited[i] == false && min > verptr->dis[i]) {
  48. min = verptr->dis[i];
  49. v = i;
  50. }
  51. }
  52. if (min == InFinity)
  53. break;
  54. verptr->visited[v] = true;
  55. auto beg = lists[v].begin();
  56. while (beg != lists[v].end()) {
  57. if (verptr->visited[*beg] == false)
  58. if (verptr->dis[v] + weight[v][*beg] < verptr->dis[*beg])
  59. verptr->dis[*beg] = verptr->dis[v] + weight[v][*beg];
  60. ++beg;
  61. }
  62. }
  63. }
  64. void Graph::Display(const size_t v)const {
  65. for (int i = 0; i < verptr->vertexnumber; ++i) {
  66. std::cout << v << " to " << i << " minweight: " << verptr->dis[i] << std::endl;
  67. }
  68. }
  69. int main(void)
  70. {
  71. const size_t vertexnumber = 7;
  72. Graph graph(vertexnumber);
  73. graph.AddEdge(0, 1, 2);
  74. graph.AddEdge(0, 2, 4);
  75. graph.AddEdge(0, 3, 1);
  76. graph.AddEdge(1, 3, 3);
  77. graph.AddEdge(1, 4, 10);
  78. graph.AddEdge(2, 5, 5);
  79. graph.AddEdge(3, 2, 2);
  80. graph.AddEdge(3, 5, 8);
  81. graph.AddEdge(3, 6, 4);
  82. graph.AddEdge(3, 4, 2);
  83. graph.AddEdge(4, 6, 6);
  84. graph.AddEdge(6, 5, 1);
  85. graph.Dijkstra(0);
  86. graph.Display(0);
  87. system("pause");
  88. }

 

还有一个问题没有解决?如果权值为负数呢?该怎么办呢?Dijkstra算法是否还可以行得通?如果不行,该怎么解决呢?

 

 

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

闽ICP备14008679号