Dijkstra 单源最短路径算法

简介:

Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年构思并于 1959 年发表。其解决的问题是:给定图 G 和源顶点 v,找到从 v 至图中所有顶点的最短路径。

Dijkstra 算法采用贪心算法(Greedy Algorithm)范式进行设计。在最短路径问题中,对于带权有向图 G = (V, E),Dijkstra 算法的初始实现版本未使用最小优先队列实现,其时间复杂度为 O(V2),基于Fibonacci heap 的最小优先队列实现版本,其时间复杂度为 O(E + VlogV)。

Bellman-Ford 算法和 Dijkstra 算法同为解决单源最短路径的算法。对于带权有向图 G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford 算法能适应一般的情况(即存在负权边的情况)。一个实现的很好的 Dijkstra 算法比 Bellman-Ford 算法的运行时间 O(V*E) 要低。

Dijkstra 算法描述:

  1. 创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
  2. 创建 SPT(Shortest Path Tree)集合 sptSet,用于存放包含在 SPT 中的顶点;
  3. 如果 sptSet 中并没有包含所有的顶点,则:
    • 选中不包含在 sptSet 中的顶点 u,u 为当前 sptSet 中未确认的最短距离顶点;
    • 将 u 包含进 sptSet;
    • 更新 u 的所有邻接顶点的距离值;

伪码实现如下:

复制代码
 1 function Dijkstra(Graph, source):
 2 
 3     dist[source] ← 0          // Distance from source to source
 4     prev[source] ← undefined  // Previous node in optimal path initialization
 5 
 6     for each vertex v in Graph:  // Initialization
 7         if v ≠ source            // Where v has not yet been removed from Q (unvisited nodes)
 8             dist[v] ← infinity   // Unknown distance function from source to v
 9             prev[v] ← undefined  // Previous node in optimal path from source
10         end if 
11         add v to Q               // All nodes initially in Q (unvisited nodes)
12     end for
13     
14     while Q is not empty:
15         u ← vertex in Q with min dist[u]  // Source node in first case
16         remove u from Q 
17         
18         for each neighbor v of u:         // where v has not yet been removed from Q.
19             alt ← dist[u] + length(u, v)
20             if alt < dist[v]:             // A shorter path to v has been found
21                 dist[v] ← alt 
22                 prev[v] ← u 
23             end if
24         end for
25     end while
26 
27     return dist[], prev[]
28 
29 end function
复制代码

例如,下面是一个包含 9 个顶点的图,每条边分别标识了距离。

源顶点 source = 0,初始时,

  • sptSet = {false, false, false, false, false, false, false, false, false};
  • distSet = {0, INF, INF, INF, INF, INF, INF, INF, INF};

将 0 包含至 sptSet 中;

  • sptSet = {true, false, false, false, false, false, false, false, false};

更新 0 至其邻接节点的距离;

  • distSet = {04, INF, INF, INF, INF, INF, 8, INF};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 1,则将 1 包含至 sptSet;

  • sptSet = {truetrue, false, false, false, false, false, false, false};

更新 1 至其邻接节点的距离;

  • distSet = {0412, INF, INF, INF, INF, 8, INF};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 7,则将 7 包含至 sptSet;

  • sptSet = {truetrue, false, false, false, false, false, true, false};

更新 7 至其邻接节点的距离;

  • distSet = {0412, INF, INF, INF, 9815};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 6,则将 6 包含至 sptSet;

  • sptSet = {truetrue, false, false, false, false, truetrue, false};

更新 6 至其邻接节点的距离;

  • distSet = {0412, INF, INF, 119815};

以此类推,直到遍历结束。

  • sptSet = {truetruetruetruetruetruetruetruetrue};
  • distSet = {04121921119814};

最终结果为源顶点 0 至所有顶点的距离:

复制代码
Vertex   Distance from Source
0                0
1                4
2                12
3                19
4                21
5                11
6                9
7                8
8                14
复制代码

C#代码实现:

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 
  5 namespace GraphAlgorithmTesting
  6 {
  7   class Program
  8   {
  9     static void Main(string[] args)
 10     {
 11       int[,] graph = new int[9, 9]
 12       {
 13         {0, 4, 0, 0, 0, 0, 0, 8, 0},
 14         {4, 0, 8, 0, 0, 0, 0, 11, 0},
 15         {0, 8, 0, 7, 0, 4, 0, 0, 2},
 16         {0, 0, 7, 0, 9, 14, 0, 0, 0},
 17         {0, 0, 0, 9, 0, 10, 0, 0, 0},
 18         {0, 0, 4, 0, 10, 0, 2, 0, 0},
 19         {0, 0, 0, 14, 0, 2, 0, 1, 6},
 20         {8, 11, 0, 0, 0, 0, 1, 0, 7},
 21         {0, 0, 2, 0, 0, 0, 6, 7, 0}
 22       };
 23 
 24       Graph g = new Graph(graph.GetLength(0));
 25       for (int i = 0; i < graph.GetLength(0); i++)
 26       {
 27         for (int j = 0; j < graph.GetLength(1); j++)
 28         {
 29           if (graph[i, j] > 0)
 30             g.AddEdge(i, j, graph[i, j]);
 31         }
 32       }
 33 
 34       int[] dist = g.Dijkstra(0);
 35       Console.WriteLine("Vertex\t\tDistance from Source");
 36       for (int i = 0; i < dist.Length; i++)
 37       {
 38         Console.WriteLine("{0}\t\t{1}", i, dist[i]);
 39       }
 40 
 41       Console.ReadKey();
 42     }
 43 
 44     class Edge
 45     {
 46       public Edge(int begin, int end, int distance)
 47       {
 48         this.Begin = begin;
 49         this.End = end;
 50         this.Distance = distance;
 51       }
 52 
 53       public int Begin { get; private set; }
 54       public int End { get; private set; }
 55       public int Distance { get; private set; }
 56     }
 57 
 58     class Graph
 59     {
 60       private Dictionary<int, List<Edge>> _adjacentEdges
 61         = new Dictionary<int, List<Edge>>();
 62 
 63       public Graph(int vertexCount)
 64       {
 65         this.VertexCount = vertexCount;
 66       }
 67 
 68       public int VertexCount { get; private set; }
 69 
 70       public void AddEdge(int begin, int end, int distance)
 71       {
 72         if (!_adjacentEdges.ContainsKey(begin))
 73         {
 74           var edges = new List<Edge>();
 75           _adjacentEdges.Add(begin, edges);
 76         }
 77 
 78         _adjacentEdges[begin].Add(new Edge(begin, end, distance));
 79       }
 80 
 81       public int[] Dijkstra(int source)
 82       {
 83         // dist[i] will hold the shortest distance from source to i
 84         int[] distSet = new int[VertexCount];
 85 
 86         // sptSet[i] will true if vertex i is included in shortest
 87         // path tree or shortest distance from source to i is finalized
 88         bool[] sptSet = new bool[VertexCount];
 89 
 90         // initialize all distances as INFINITE and stpSet[] as false
 91         for (int i = 0; i < VertexCount; i++)
 92         {
 93           distSet[i] = int.MaxValue;
 94           sptSet[i] = false;
 95         }
 96 
 97         // distance of source vertex from itself is always 0
 98         distSet[source] = 0;
 99 
100         // find shortest path for all vertices
101         for (int i = 0; i < VertexCount - 1; i++)
102         {
103           // pick the minimum distance vertex from the set of vertices not
104           // yet processed. u is always equal to source in first iteration.
105           int u = CalculateMinDistance(distSet, sptSet);
106 
107           // mark the picked vertex as processed
108           sptSet[u] = true;
109 
110           // update dist value of the adjacent vertices of the picked vertex.
111           for (int v = 0; v < VertexCount; v++)
112           {
113             // update dist[v] only if is not in sptSet, there is an edge from 
114             // u to v, and total weight of path from source to  v through u is 
115             // smaller than current value of dist[v]
116             if (!sptSet[v]
117               && distSet[u] != int.MaxValue
118               && _adjacentEdges[u].Exists(e => e.End == v))
119             {
120               int d = _adjacentEdges[u].Single(e => e.End == v).Distance;
121               if (distSet[u] + d < distSet[v])
122               {
123                 distSet[v] = distSet[u] + d;
124               }
125             }
126           }
127         }
128 
129         return distSet;
130       }
131 
132       /// <summary>
133       /// A utility function to find the vertex with minimum distance value, 
134       /// from the set of vertices not yet included in shortest path tree
135       /// </summary>
136       private int CalculateMinDistance(int[] distSet, bool[] sptSet)
137       {
138         int minDistance = int.MaxValue;
139         int minDistanceIndex = -1;
140 
141         for (int v = 0; v < VertexCount; v++)
142         {
143           if (!sptSet[v] && distSet[v] <= minDistance)
144           {
145             minDistance = distSet[v];
146             minDistanceIndex = v;
147           }
148         }
149 
150         return minDistanceIndex;
151       }
152     }
153   }
154 }
复制代码

参考资料







本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/p/dijkstra_algorithm.html,如需转载请自行联系原作者

目录
相关文章
|
1月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
70 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
1月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
3月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
3月前
|
自然语言处理 算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
58 0
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
|
4月前
|
算法 Java
Java语言实现最短路径算法(Shortest Path)
Java语言实现最短路径算法(Shortest Path)
60 3
|
3月前
|
算法 定位技术
路径规划算法 - 求解最短路径 - A*(A-Star)算法
路径规划算法 - 求解最短路径 - A*(A-Star)算法
78 0
|
3月前
|
算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
66 0
|
4月前
|
算法 Java C++
《经典图论算法》迪杰斯特拉算法(Dijkstra)
这个是求最短路径的迪杰斯特拉算法,另外我还写了50多种《经典图论算法》,每种都使用C++和Java两种语言实现,熟练掌握之后无论是参加蓝桥杯,信奥赛,还是其他比赛,或者是面试,都能轻松应对。
|
28天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
13天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。