首页 > Java > java教程 > Java中关于最短路径算法之Dijkstra算法的实现

Java中关于最短路径算法之Dijkstra算法的实现

黄舟
发布: 2017-10-13 10:29:18
原创
3040 人浏览过

这篇文章主要介绍了java实现最短路径算法之Dijkstra算法, Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法,有兴趣的可以了解一下

前言

Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法。该算法被称为是“贪心算法”的成功典范。本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码。

一、知识准备:

1、表示图的数据结构

用于存储图的数据结构有多种,本算法中笔者使用的是邻接矩阵。

图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。

设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

从上面可以看出,无向图的边数组是一个对称矩阵。所谓对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。

从这个矩阵中,很容易知道图中的信息。

(1)要判断任意两顶点是否有边无边就很容易了;

(2)要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;

(3)求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点;

而有向图讲究入度和出度,顶点vi的入度为1,正好是第i列各数之和。顶点vi的出度为2,即第i行的各数之和。

有向图的定义也类似,故不做赘述。

2、单起点全路径

所谓单起点全路径,就是指在一个图中,从一个起点出发,到所有节点的最短路径。 

3、图论的基本知识(读者需自行寻找相关资料)

4、互补松弛条件

设标量d1,d2,....,dN满足

dj<=di + aij, (i,j)属于A,

且P是以i1为起点ik为终点的路,如果

dj = di + aij, 对P的所有边(i, j)

成立,那么P是从i1到ik的最短路。其中,满足上面两式的被称为最短路问题的互补松弛条件。

二、算法思想

1、令G = (V,E)为一个带权无向图。G中若有两个相邻的节点,i和j。aij(在这及其后面都表示为下标,请注意)为节点i到节点j的权值,在本算法可以理解为距离。每个节点都有一个值di(节点标记)表示其从起点到它的某条路的距离。

2、算法初始有一个数组V用于储存未访问节点的列表,我们暂称为候选列表。选定节点1为起始节点。开始时,节点1的d1=0, 其他节点di=无穷大,V为所有节点。
初始化条件后,然后开始迭代算法,直到V为空集时停止。具体迭代步骤如下:

将d值最小的节点di从候选列表中移除。(本例中V的数据结构采用的是优先队列实现最小值出列,最好使用斐波那契对,在以前文章有过介绍,性能有大幅提示)。对于以该节点为起点的每一条边,不包括移除V的节点, (i, j)属于A, 若dj > di + aij(违反松弛条件),则令

dj = di + aij    , (如果j已经从V中移除过,说明其最小距离已经计算出,不参与此次计算)

可以看到在算法的运算工程中,节点的d值是单调不增的

具体算法图解如下

  

三、java代码实现


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

public class Vertex implements Comparable<Vertex>{

 

  /**

   * 节点名称(A,B,C,D)

   */

  private String name;

   

  /**

   * 最短路径长度

   */

  private int path;

   

  /**

   * 节点是否已经出列(是否已经处理完毕)

   */

  private boolean isMarked;

   

  public Vertex(String name){

    this.name = name;

    this.path = Integer.MAX_VALUE; //初始设置为无穷大

    this.setMarked(false);

  }

   

  public Vertex(String name, int path){

    this.name = name;

    this.path = path;

    this.setMarked(false);

  }

   

  @Override

  public int compareTo(Vertex o) {

    return o.path > path?-1:1;

  }

}

登录后复制


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

public class Graph {

 

  /*

   * 顶点

   */

  private List<Vertex> vertexs;

 

  /*

   * 边

   */

  private int[][] edges;

 

  /*

   * 没有访问的顶点

   */

  private Queue<Vertex> unVisited;

 

  public Graph(List<Vertex> vertexs, int[][] edges) {

    this.vertexs = vertexs;

    this.edges = edges;

    initUnVisited();

  }

   

  /*

   * 搜索各顶点最短路径

   */

  public void search(){

    while(!unVisited.isEmpty()){

      Vertex vertex = unVisited.element();

      //顶点已经计算出最短路径,设置为"已访问"

       vertex.setMarked(true); 

      //获取所有"未访问"的邻居

        List<Vertex> neighbors = getNeighbors(vertex); 

      //更新邻居的最短路径

      updatesDistance(vertex, neighbors);   

      pop();

    }

    System.out.println("search over");

  }

   

  /*

   * 更新所有邻居的最短路径

   */

  private void updatesDistance(Vertex vertex, List<Vertex> neighbors){

    for(Vertex neighbor: neighbors){

      updateDistance(vertex, neighbor);

    }

  }

   

  /*

   * 更新邻居的最短路径

   */

  private void updateDistance(Vertex vertex, Vertex neighbor){

    int distance = getDistance(vertex, neighbor) + vertex.getPath();

    if(distance < neighbor.getPath()){

      neighbor.setPath(distance);

    }

  }

 

  /*

   * 初始化未访问顶点集合

   */

  private void initUnVisited() {

    unVisited = new PriorityQueue<Vertex>();

    for (Vertex v : vertexs) {

      unVisited.add(v);

    }

  }

 

  /*

   * 从未访问顶点集合中删除已找到最短路径的节点

   */

  private void pop() {

    unVisited.poll();

  }

 

  /*

   * 获取顶点到目标顶点的距离

   */

  private int getDistance(Vertex source, Vertex destination) {

    int sourceIndex = vertexs.indexOf(source);

    int destIndex = vertexs.indexOf(destination);

    return edges[sourceIndex][destIndex];

  }

 

  /*

   * 获取顶点所有(未访问的)邻居

   */

  private List<Vertex> getNeighbors(Vertex v) {

    List<Vertex> neighbors = new ArrayList<Vertex>();

    int position = vertexs.indexOf(v);

    Vertex neighbor = null;

    int distance;

    for (int i = 0; i < vertexs.size(); i++) {

      if (i == position) {

        //顶点本身,跳过

        continue;

      }

      distance = edges[position][i];  //到所有顶点的距离

      if (distance < Integer.MAX_VALUE) {

        //是邻居(有路径可达)

        neighbor = getVertex(i);

        if (!neighbor.isMarked()) {

          //如果邻居没有访问过,则加入list;

          neighbors.add(neighbor);

        }

      }

    }

    return neighbors;

  }

 

  /*

   * 根据顶点位置获取顶点

   */

  private Vertex getVertex(int index) {

    return vertexs.get(index);

  }

 

  /*

   * 打印图

   */

  public void printGraph() {

    int verNums = vertexs.size();

    for (int row = 0; row < verNums; row++) {

      for (int col = 0; col < verNums; col++) {

        if(Integer.MAX_VALUE == edges[row][col]){

          System.out.print("X");

          System.out.print(" ");

          continue;

        }

        System.out.print(edges[row][col]);

        System.out.print(" ");

      }

      System.out.println();

    }

  }

}

登录后复制


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

public class Test {

 

  public static void main(String[] args){

    List<Vertex> vertexs = new ArrayList<Vertex>();

    Vertex a = new Vertex("A", 0);

    Vertex b = new Vertex("B");

    Vertex c = new Vertex("C");

    Vertex d = new Vertex("D");

    Vertex e = new Vertex("E");

    Vertex f = new Vertex("F");

    vertexs.add(a);

    vertexs.add(b);

    vertexs.add(c);

    vertexs.add(d);

    vertexs.add(e);

    vertexs.add(f);

    int[][] edges = {

        {Integer.MAX_VALUE,6,3,Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE},

        {6,Integer.MAX_VALUE,2,5,Integer.MAX_VALUE,Integer.MAX_VALUE},

        {3,2,Integer.MAX_VALUE,3,4,Integer.MAX_VALUE},

        {Integer.MAX_VALUE,5,3,Integer.MAX_VALUE,5,3},

        {Integer.MAX_VALUE,Integer.MAX_VALUE,4,5,Integer.MAX_VALUE,5},

        {Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,3,5,Integer.MAX_VALUE}

     

    };

    Graph graph = new Graph(vertexs, edges);

    graph.printGraph();

    graph.search();

  }

   

}

登录后复制

以上是Java中关于最短路径算法之Dijkstra算法的实现的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板