Dijkstra算法是一种用于解决单源最短路径问题的经典算法,由荷兰计算机科学家Edsger W. Dijkstra于1956年提出。它可以找到从起始节点到所有其他节点的最短路径。
基本介绍
该算法的基本思想是通过逐步扩展节点的方式,逐渐确定从起始节点到其他节点的最短路径。算法维护两个集合:一个是已确定最短路径的节点集合,记为S;另一个是还未确定最短路径的节点集合,记为V-S。
算法步骤:
创建一个距离表,用于记录起始节点到各个节点的当前最短距离。起始节点的最短距离初始化为0,其他节点的最短距离初始化为无穷大(或一个很大的数)。
选择起始节点作为当前节点,并将其加入已确定最短路径的节点集合S。
对于当前节点的所有邻居节点,更新它们的最短距离。具体步骤如下:
- 遍历当前节点的所有邻居节点。
- 对于每个邻居节点,计算从起始节点经过当前节点到达该邻居节点的距离。如果该距离小于该邻居节点当前的最短距离,则更新最短距离。
从未确定最短路径的节点集合V-S中选择一个距离最小的节点作为新的当前节点,并将其加入已确定最短路径的节点集合S。
重复步骤3和步骤4,直到所有节点都被加入到已确定最短路径的节点集合S中,或者无法找到更短的路径。
最终,距离表中记录的即为起始节点到各个节点的最短距离。
Dijkstra算法的关键在于每次选择距离最小的节点作为当前节点,并通过更新邻居节点的最短距离来逐步扩展最短路径。该算法基于贪心策略,每次选择当前最优解,因此可以找到最短路径。
需要注意的是,Dijkstra算法要求图中的边权重非负,且对于有向图和无向图都适用。如果图中存在负权边,可以使用其他算法,如Bellman-Ford算法或SPFA算法来解决最短路径问题。
举例
以D为开头,求D到各个点的最短距离。
第1步:初始化距离,其实指与D直接连接的点的距离。dis[c]代表D到C点的最短距离,因而初始dis[C]=3,dis[E]=4,dis[D]=0,其余为无穷大。设置集合S用来表示已经找到的最短路径。此时,S={D}。现在得到D到各点距离 {D(0),C(3),E(4),F(*),G(*),B(*),A(*)} ,其中*代表未知数也可以说是无穷大,括号里面的数值代表D点到该点的最短距离。
第2步:不考虑集合S中的值,因为dis[C]=3,是当中距离最短的,所以此时更新S,S={D,C} 。接着我们看与C连接的点,分别有B,E,F,已经在集合S中的不看,dis[C-B]=10,因而dis[B]=dis[C]+10=13,dis[F]=dis[C]+dis[C-F]=9,dis[E]=dis[C]+dis[C-E]=3+5=8>4 (初始化时的dis[E]=4) 不更新。此时 {D(0),C(3),E(4),F(9),G(*),B(13),A(*)}。
第3步:在第2步中,E点的值4最小,更新S={D,C,E} ,此时看与E点直接连接的点,分别有F,G。dis[F]=dis[E]+dis[E-F]=4+2=6(比原来的值小,得到更新),dis[G]=dis[E]+dis[E-G]=4+8=12(更新)。此时 {D(0),C(3),E(4),F(6),G(12),B(13),A(*)} 。
第4步:在第3步中,F点的值6最小,更新S={D,C,E,F} ,此时看与F点直接连接的点,分别有B,A,G。dis[B]=dis[F]+dis[F-B]=6+7=13,dis[A]=dis[F]+dis[F-A]=6+16=22,dis[G]=dis[F]+dis[F-G]=6+9=15>12(不更新)。此时 {D(0),C(3),E(4),F(6),G(12),B(13),A(22)}.
第5步:在第4步中,G点的值12最小,更新S={D,C,E,F,G} ,此时看与G点直接连接的点,只有A。dis[A]=dis[G]+dis[G-A]=12+14=26>22(不更新)。 {D(0),C(3),E(4),F(6),G(12),B(13),A(22)}.
第6步:在第5步中,B点的值13最小,更新S={D,C,E,F,G,B} ,此时看与B点直接连接的点,只有A。dis[A]=dis[B]+dis[B-A]=13+12=25>22(不更新)。 {D(0),C(3),E(4),F(6),G(12),B(13),A(22)}.
第6步:最后只剩下A值,直接进入集合S={D,C,E,F,G,B,A} ,此时所有的点都已经遍历结束,得到最终结果 {D(0),C(3),E(4),F(6),G(12),B(13),A(22)}.
JAVA实现
上述案例的JAVA实现
import java.util.Arrays;
public class DijkstraAlgorithm {
private static int minDistance(int[] dist, boolean[] visited) {
int min = Integer.MAX_VALUE;
int minIndex = -1;
for (int i = 0; i < dist.length; i++) {
if (!visited[i] && dist[i]