Dijkstra算法介绍:
需求:
求某个点到图中各个点的最短路径。
这里我自己画了一个图来方便学习。
求A节点到其他各个节点要走的最短长度。为了方便描述,我将图抽象成这个样子。
介绍:
- 迪杰斯特拉算法用于求单源的最短路径问题
- 迪杰斯特拉不适用于边的权值存在负数的图
算法思路:
- 将所有的节点分为两类,一类是已经确定了到目的地最短路径的节点,一类是没有确定的
- 定义一个数组,用来保存所有点到目的节点的最短距离。
- 每次遍历,从没有确定的节点中找到一个节点,放到已经确定的节点中,并在添加进去的时候,维护所有与这个点有联系的节点到目的节点的最短距离
- 直到所有的节点放到确定点的集合中为止。
如何在没有确定的点中找一个确定的点
值得注意的是,我们如何在所有没有确定的节点中找出一个节点将其定义为已经确定的点呢?
我们的策略是遍历所有未确定的节点,找到其中距离目标节点最近的节点,这个距离一定是这个节点确定的最短距离。
为什么呢?举一个例子可以说明。
比如上面的图,从A为起始节点。
- 将A放入确定的点中,不确定的节点中,B,C到目的地的距离分别是4,1,其他节点都是INF
- 从除了A以外的其他节点中选择最小的,既C,并维护其他节点,这里将E维护为6
- 再从除A,C之外的所有节点中选择节点,这里就选到了B,距离为4,并维护其他节点,这里就会将E维护为5,比6更优,其他都是INF
- 重复上面的行为即可。
有了上面的例子,就可以理解为什么在没有确定的节点中,选择距离目标节点最小的节点放到确定的集合中是正确的了。
如果还是不能理解的话,我们可以做这么一个假设,将所有已经确定的节点看做是一个节点,其他节点到目标节点的距离看做是到总的那个节点的距离。那么就相当于是与总的节点直接相连,自然是确定的最短距离,当然如果是距离第二近的话,就不一定是直接相连了,可能这样会好理解一点。
具体实现:
/**
* 使用迪杰斯特拉算法求单源的最短路径,节点从0开始标记
* @param G 图的邻接矩阵
* @param startPoint 出发节点(从0开始计数)
* @param maxSize 图中共包含多少个节点(从1开始计数)例如有0,1,2三个节点,则maxSize应该等于3
*/
public int[] Dijkstra(int[][] G,int startPoint,int maxSize){
final int INF = Integer.MAX_VALUE/2;
//re[i]表示i号节点到目标节点的最短距离
int[] re = new int[maxSize];
Arrays.fill(re,INF);
re[startPoint]=0;
boolean[] Visited = new boolean[maxSize];
for(int i=0;i<maxSize;i++){
int x = -1;
for(int y = 0;y<maxSize;y++){
if(!Visited[y]&&(x==-1||re[y]<re[x])){
x=y;
}
}
Visited[x] = true;
for(int y=0;y<maxSize;y++){
if(!Visited[y]){
re[y] = Math.min(re[y],re[x]+G[x][y]);
}
}
}
return re;
}