图的单源最短路径(Dijkstra算法)

忘是亡心i 2023-07-22 03:46 146阅读 0赞

单源最短路径问题

  1. 如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径各边上的权值总和达到最小。

Dijkstra算法由来

  1. 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

算法的具体思想

辅助数组

①采用一个path[]数组来存储路径:path[a] = b 表示最短路径中顶点a的上一顶点为b;
②采用一个info[]数组来存储各个顶点到源点的最短距离,同时此数组也有着标记的作用,即info[x]=0时,表示x顶点已经在路径中。

具体流程

①初始化辅助数组,确定源点(orign)

②使用图中的结构来对辅助数组中的最短距离进行更新:
Ⅰ、对于能到达的点:info[x] = map[orign][x];并且将这些点的前置点设为源点:path[x]=orign
Ⅱ、对于不能到达的点:info[x] = ∞

③定位info数组中权值最小(除0,0表示已加入)的点(min),取出最小权值minInfo,将该点加入路径,设置info[min]=0,并根据min顶点,对辅助数组中未加入的顶点进行更新:
若minInfo+map[min][x] < info[x],则使得info[x] = minInfo+map[min][x],并将路径中x顶点的前置顶点设置为min顶点
Ps:此步可将minInfo对应的权值大小进行存储,即源点到该点的最短路径长度。

④重复操作步骤③,直至所有顶点最短路径都得出,即数组info[]所有值都为零

输出路径

在path[]数组中存储着路径的具体信息:最短路径中当前顶点的前置路径
可使用栈的特性将其中数据取出来:

  1. path[] = dijkstra(sMap, 1);
  2. int end = 5;
  3. //借助栈的特性
  4. int stack[] = new int[sMap.num];
  5. int top = 0;
  6. end--; //从零开始
  7. while(end != -1) {
  8. stack[top++] = end;
  9. end = path[end];
  10. }
  11. System.out.print(stack[--top]+1);
  12. while(top > 0) {
  13. //位置比索引大一
  14. System.out.print("---->"+(stack[--top]+1));
  15. }

代码实现

  1. /**
  2. * 得出最小路径表
  3. * @param map 用二维数组存储的图结构
  4. * @return 路径数组
  5. */
  6. public static int[] dijkstra(SimpleMap sMap,int first) {
  7. //路径数组
  8. int[] path = new int[sMap.num];
  9. //标记与权值数组(权值为0,表示已加入路径)
  10. int[] markAndInfo = new int[sMap.num];
  11. //辅助数组初始化
  12. for(int i=0; i<sMap.num; i++) {
  13. path[i] = -1;
  14. markAndInfo[i]= CreateAMap.MAX;
  15. }
  16. //定位初始位置(从零开始)
  17. first = first-1;
  18. for(int j=0; j<sMap.num; j++) {
  19. if(j != first) {
  20. path[j] = first;
  21. }
  22. markAndInfo[j]= sMap.map[first][j];
  23. }
  24. //已经加入到路径的顶点
  25. int judge = 1;
  26. while(judge < sMap.num) {
  27. //从权值数组中找出最小的的值
  28. int index = 0;
  29. int min = CreateAMap.MAX;
  30. for(int i=0; i<sMap.num; i++) {
  31. //需判断当前点是否已经在路径中
  32. if(markAndInfo[i] != 0 && markAndInfo[i] < min) {
  33. index = i;
  34. min = markAndInfo[i];
  35. }
  36. }
  37. //更新权值数组以及路径数组
  38. markAndInfo[index] = 0;
  39. for (int i = 0; i < sMap.num; i++) {
  40. if(markAndInfo[i] !=0 && min+sMap.map[index][i] < markAndInfo[i]) {
  41. markAndInfo[i] = min+sMap.map[index][i];
  42. path[i] = index;
  43. }
  44. }
  45. judge++;
  46. }
  47. return path;
  48. }

测试图及其结果:
在这里插入图片描述
源点为1,终点为5:
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,146人围观)

还没有评论,来说两句吧...

相关阅读