Dijkstra求有權圖最短路徑長度並打印

1、簡介

迪克斯特拉算法主要特色是以起始點爲中心向外層層擴展,直到擴展到終點爲止,就像剝洋蔥同樣,因此它也屬於廣度優先搜索。java

2、算法正確性證實

老哥們本身找吧,網上沒找到一篇能讓我徹底滿意的證實node

3、JAVA代碼實現

clipboard.png

public class Dijkstra {

  public static final int INF = 65535;

  public static final String RIGHT_ARROW = "-->";

  public static final String LEFT_ARROW = "<--";

  public static void main(String[] args) {

    getShortestDistance(new int[][]{
            {0, INF, 10, INF, 30, 100},
            {INF, 0, 5, INF, INF, INF},
            {INF, INF, 0, 50, INF, INF},
            {INF, INF, INF, 0, INF, 10},
            {INF, INF, INF, 20, 0, 60},
            {INF, INF, INF, INF, INF, 0}
    }, 0);
  }

  private static void getShortestDistance(int[][] matrix, int start) {
    boolean[] visited = new boolean[matrix.length]; // 節點是否已被訪問
    int[] distance = new int[matrix.length]; // 距離數組
    int[] pre = new int[matrix.length]; // 前驅數組,用於記錄路徑信息

    // 初始化距離數組、前驅數組,訪問數組
    for (int j = 0; j < matrix[start].length; j++) {
      distance[j] = matrix[start][j];
      if (distance[j] == INF) {
        pre[j] = -1;
      } else {
        pre[j] = start;
      }

      visited[j] = false;
    }

    // 初始節點設置爲已訪問
    visited[start] = true;
    int k = start;
    while (k != -1) {
      visited[k] = true;

      for (int j = 0; j < matrix[k].length; j++) {
        if (matrix[k][j] + distance[k] < distance[j]) {
          distance[j] = matrix[k][j] + distance[k];
          pre[j] = k;
        }
      }

      // 獲取下一個距離起始節點最近的未被訪問的節點
      k = getNextNodeIndex(visited, distance);
    }

    // 打印最短距離和路徑
    printShortestPath(distance, pre, start);
  }

  private static void printShortestPath(int[] distance, int[] pre, int start) {
    for (int i = 0; i < distance.length; i++) {
      StringBuilder sb = new StringBuilder();
      sb.append(getNodeName(start));
      sb.append(RIGHT_ARROW);
      sb.append(getNodeName(i));

      if (distance[i] < INF) {
        sb.append("最短距離:");
        sb.append(distance[i]);
        sb.append("\t");
      } else {
        sb.append("不通");
        continue;
      }

      sb.append("最短路徑");
      sb.append(getNodeName(i));
      sb.append(LEFT_ARROW);

      int j = i;
      do {
        j = pre[j];
        sb.append(getNodeName(j));
        sb.append(LEFT_ARROW);
      } while (pre[j] != -1 && j != start);

      System.out.println(sb.substring(0, sb.lastIndexOf(LEFT_ARROW)));
    }
  }

  private static int getNextNodeIndex(boolean[] visited, int[] distance) {
    int min = INF;
    int k = -1;
    for (int i = 0; i < distance.length; i++) {
      if (distance[i] < min && !visited[i]) {
        min = distance[i];
        k = i;
      }
    }

    return k;
  }

  private static String getNodeName(int nodeIdx) {
    return "v" + (nodeIdx + 1);
  }
結果打印:
v1-->v1最短距離:0    最短路徑v1<--v1
v1-->v3最短距離:10    最短路徑v3<--v1
v1-->v4最短距離:50    最短路徑v4<--v5<--v1
v1-->v5最短距離:30    最短路徑v5<--v1
v1-->v6最短距離:60    最短路徑v6<--v4<--v5<--v1

4、擴展

我另外想了一種方法來實現尋找最短路徑,相似迪克斯特拉算法,只不過將廣度優先搜索變爲深度優先搜索算法

public class DetectShotestDistance {

  public static final int INF = 65535;

  public static final String RIGHT_ARROW = "-->";

  public static final String LEFT_ARROW = "<--";

  public static void main(String[] args) {

    getShortestDistance(new int[][]{
            {0, INF, 10, INF, 30, 100},
            {INF, 0, 5, INF, INF, INF},
            {INF, INF, 0, 50, INF, INF},
            {INF, INF, INF, 0, INF, 10},
            {INF, INF, INF, 20, 0, 60},
            {INF, INF, INF, INF, INF, 0}
    }, 0);
  }

  private static void getShortestDistance(int[][] matrix, int start) {
    Set visited = new HashSet<>();
    int[] distance = new int[matrix.length];
    int[] pre = new int[matrix.length];

    // 初始化距離數組和路徑數組
    for (int j = 0; j < matrix[start].length; j++) {
      distance[j] = matrix[start][j];
      if (distance[j] == INF) {
        pre[j] = -1;
      } else {
        pre[j] = start;
      }
    }

    int curIdx = start;
    visited.add(curIdx);
    int nextIdx = getNextNodeIndex(start, matrix, visited, distance, pre);
    while (nextIdx != -1) {
      visited.add(nextIdx);

      if (matrix[curIdx][nextIdx] + distance[curIdx] < distance[nextIdx]) {
        distance[nextIdx] = matrix[curIdx][nextIdx] + distance[curIdx];
      }

      curIdx = nextIdx;
      nextIdx = getNextNodeIndex(nextIdx, matrix, visited, distance, pre);
    }

    for (int i = 0; i < distance.length; i++) {
      StringBuilder sb = new StringBuilder();
      sb.append(getNodeName(start));
      sb.append(RIGHT_ARROW);
      sb.append(getNodeName(i));

      if (distance[i] < INF) {
        sb.append("最短距離:");
        sb.append(distance[i]);
        sb.append("\t");
      } else {
        sb.append("不通");
        continue;
      }

      sb.append("最短路徑");
      sb.append(getNodeName(i));
      sb.append(LEFT_ARROW);

      int j = i;
      do {
        j = pre[j];
        sb.append(getNodeName(j));
        sb.append(LEFT_ARROW);
      } while (pre[j] != -1 && j != start);

      System.out.println(sb.substring(0, sb.lastIndexOf(LEFT_ARROW)));
    }

  }

  private static int getNextNodeIndex(int curIdx, int[][] matrix, Set visited, int[] distance, int[] pre) {
    int min = INF;
    int minIdx = -1;
    for (int j = 0; j < matrix[curIdx].length; j++) {
      if (matrix[curIdx][j] < min && !visited.contains(j)) {
        min = matrix[curIdx][j];
        minIdx = j;
        pre[minIdx] = curIdx;
      }
    }

    if (minIdx == -1) {
      for (int j = 0; j < distance.length; j++) {
        if (distance[j] != INF && !visited.contains(j)) {
          return j;
        }
      }
    }

    return minIdx;
  }

  private static String getNodeName(int nodeIdx) {
    return "v" + (nodeIdx + 1);
  }
結果打印:
v1-->v1最短距離:0    最短路徑v1<--v1
v1-->v3最短距離:10    最短路徑v3<--v1
v1-->v4最短距離:50    最短路徑v4<--v5<--v1
v1-->v5最短距離:30    最短路徑v5<--v1
v1-->v6最短距離:60    最短路徑v6<--v4<--v5<--v1
相關文章
相關標籤/搜索