Java带权图的最短路径算法-Dijkstra

Java带权图的最短路径算法-Dijkstra

Dijkstra算法的核心思想是通过逐步逼近的方式,找出从起点到图中其他所有节点的最短路径。算法的基本步骤如下:

  1. 初始化

    • 创建一个最短路径信息数组shortPath[x][3],每一个一维数组含义为当前结点、该节点到此节点的最短路径、起始节点。
    • 初始化shortPath数组,shortPath[x][0]当前节点编号、shortPath[x][1]最短路径、shortPath[x][2]起始结点编号
    • 初始化优先队列,将起始节点的所有邻接点加入到优先队列中,结点信息使用Ownership类,属性值{time、nodeIndex、weight}。
    • 创建优先队列,优先队列按照结点的权重值优先出队 PriorityQueue。
    • 创建优先队列的比较器OwnershipCustomerComparator类,通过weight大小进行优先出队。
  2. 流程:

    1. 优先队列为空则退出
    2. 遍历优先队列,将队列中time版本对应的结点信息值写入shortPath中。每次拿到最新路径长度newWeight=matrix[up - 1][ownership.nodeIndex] + shortPath[up - 1][1](起始节点最短路径+起始节点到当前节点一条边的权重),如果当前结点未被初始化则直接将newWeight写入shortPath数组中,如果当前节点已经被写过最短路径,则直接略过当前newWeight即可,这里有一个dtx变量,记录当前优先队列中结点是否被写如果shortPath,用于time(版本)。
    3. 遍历优先队列(需要出队),将权重最小的结点出队,将该节点下的所有邻接点拿出做以下操作步骤:
      1. 需要是出对节点的邻接点
      2. 邻接点在shortPath表中的最短路径未被初始化(还是无穷大),将结点信息写入,最短路径为出对节点权重+出对节点到达该邻接点的权重
      3. 查看该邻接点是否出现在优先队列中。在优先队列中则更新shortPath数组以及优先队列中该结点的权重以及起始节点的信息。
      4. 优先队列中没有,Math.min(newWeight, shortPath[i][1]),取最优路径写入

    在这里插入图片描述

    代码

    public static void ownership_graph() {
      DirectGraph graph = new DirectGraph(new String[]{"V1", "V2", "V3", "V4", "V5"}, true);
      graph.addEdge(1, 2, 10);
      graph.addEdge(1, 4, 30);
      graph.addEdge(1, 5, 90);
      graph.addEdge(2, 3, 50);
      graph.addEdge(3, 5, 10);
      graph.addEdge(4, 2, 10);
      graph.addEdge(4, 3, 20);
      graph.addEdge(4, 5, 60);
      int[][] shortPath = graph.dijkstraShortFinding(1);
      for (int i = 0; i < shortPath.length; i++) {
        System.out.printf("V1 -> V%d 的最短路径为: %d\n", i + 1, shortPath[i][1]);
      }
    }
    
    /**
     * 有向图
     * @author sean
     * @version 1.0
     * @date 2024-3-19 15:34
     */
    public class DirectGraph {
        /**
         * 结点集合
         */
        private List<String> node;
    
        /**
         * true 有权图
         * false 无权图
         */
        private boolean weightFlag;
    
        /**
         * 邻接矩阵
         */
        private int[][] matrix;
      
        public DirectGraph(String[] nodes, boolean weightFlag) {
          node = new ArrayList<>(Arrays.asList(nodes));
          matrix = new int[node.size()][node.size()];
          this.weightFlag = weightFlag;
        }
      
      	/**
         * 有权图的最短路径
         * @param x 起始结点
         * @return 有权图最短路径 说明数组
         */
        public int[][] dijkstraShortFinding(int x) {
            if (this.weightFlag) {
                // 优先队列
                PriorityQueue<Ownership> queue = new PriorityQueue<>(new OwnershipCustomerComparator());
                for (int i = 0; i < matrix[x - 1].length; i++) {
                    if (matrix[x - 1][i] != 0) {
                        queue.offer(new Ownership(1, i, matrix[x - 1][i]));
                    }
                }
                // queue -> v1 v6
                int[][] shortPath = new int[node.size()][3];
                initOwnershipShortPath(shortPath);
                // 表示被访问过  表示到2的距离  表示目的节点编号从1开始
                shortPath[x - 1][1] = 0;
                shortPath[x - 1][2] = x;
                ownershipShortPath(shortPath, queue, x, 0);
                return shortPath;
            }
            return new int[node.size()][3];
        }
      	/**
         * 初始化有权数组
         * @param shortPath 最短路径数组
         */
        private void initOwnershipShortPath(int[][] shortPath) {
            for (int i = 0; i < shortPath.length; i++) {
                shortPath[i][0] = i + 1;
                shortPath[i][1] = -1;
                shortPath[i][2] = 0;
            }
        }
      
      /**
         * 有权图的最短路径
         * @param shortPath 最短路径数组
         * @param queue 按照权值的优先队列
         * @param up 起始节点
         * @param time 版本号 是否需要修改当前结点在 shortPath中的属性
         */
        private void ownershipShortPath(int[][] shortPath, PriorityQueue<Ownership> queue, int up, int time) {
            if (queue.isEmpty()) {
                return;
            }
            int dtx = 0;
            for (Ownership ownership : queue) {
                if (ownership.time != time + 1) {
                    continue;
                }
                // 新的路径长度
                int newWeight = matrix[up - 1][ownership.nodeIndex] + shortPath[up - 1][1];
                // 总是拿到最优路径
                if (shortPath[ownership.nodeIndex][1] == -1) {
                    shortPath[ownership.nodeIndex][1] = newWeight;
                    shortPath[ownership.nodeIndex][2] = up;
                } else {
                    if (shortPath[ownership.nodeIndex][1] >= newWeight) {
                        shortPath[ownership.nodeIndex][1] = newWeight;
                        shortPath[ownership.nodeIndex][2] = up;
                    }
                }
                dtx = 1;
            }
    
            // 遍历优先队列
            while (!queue.isEmpty()) {
                // 删除的结点
                Ownership removeNode = queue.poll();
                // 该节点是否影响其他结点
                boolean flag = false;
                for (int i = 0; i < matrix[removeNode.nodeIndex].length; i++) {
                    int newWeight = removeNode.weight + matrix[removeNode.nodeIndex][i];
                    // 当前节点的邻接点 必要条件
                    if (matrix[removeNode.nodeIndex][i] != 0) {
                        // 当前邻接点的最小距离 为 无穷大 就直接将当前路径长度放入
                        if (shortPath[i][1] == -1) {
                            queue.offer(new Ownership(removeNode.time + dtx, i, newWeight));
                            flag = true;
                            continue;
                        }
                        if (newWeight > shortPath[i][1]) {
                            continue;
                        }
                        // 优先队列中包含了当前结点  并且  路径为最优
                        if (queue.contains(new Ownership(i))) {
                            // 更新队列中结点的权值 和 最短路径数组中的属性
                            for (Ownership ownership : queue) {
                                if (ownership.nodeIndex == i) {
                                    ownership.weight = newWeight;
                                    shortPath[i][2] = removeNode.nodeIndex + 1;
                                    shortPath[i][1] = ownership.weight;
                                    break;
                                }
                            }
                        } else {
                            queue.offer(new Ownership(removeNode.time + dtx, i, newWeight));
                            flag = true;
                        }
                    }
                }
                // 可影响其他结点 在进行 递归回溯
                if (flag) {
                    ownershipShortPath(shortPath, queue, removeNode.nodeIndex + 1, time + 1);
                }
            }
        }
      
      	/**
         * 有点队列比较器
         */
        static class OwnershipCustomerComparator implements Comparator<Ownership>{
            @Override
            public int compare(Ownership o1, Ownership o2) {
                return o1.weight - o2.weight;
            }
        }
    
        /**
         * 结点信息
         */
        static class Ownership{
            int time;
            int nodeIndex;
            int weight;
          
            public Ownership(int nodeIndex, int weight) {
                this.nodeIndex = nodeIndex;
                this.weight = weight;
            }
    
            public Ownership(int time, int nodeIndex, int weight) {
                this.time = time;
                this.nodeIndex = nodeIndex;
                this.weight = weight;
            }
    
            public Ownership(int nodeIndex) {
                this.nodeIndex = nodeIndex;
            }
    
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
                Ownership ownership = (Ownership) o;
                return nodeIndex == ownership.nodeIndex;
            }
        }
    }
    
    ## 结果
    V1 -> V1 的最短路径为: 0
    V1 -> V2 的最短路径为: 10
    V1 -> V3 的最短路径为: 50
    V1 -> V4 的最短路径为: 30
    V1 -> V5 的最短路径为: 60
    

    初学图论算法,在B站看到有博主讲的思路,就模拟下来啦,感觉代码写的很多冗余,希望大佬指点,感谢🙇‍🙇‍

  • 45
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是带权最短路径算法——Dijkstra算法Java实现: ```java import java.util.*; public class DijkstraAlgorithm { private static final int MAX = Integer.MAX_VALUE; public static void dijkstra(int[][] graph, int src) { int n = graph.length; int[] dist = new int[n]; boolean[] visited = new boolean[n]; // 初始化dist数组和visited数组 for (int i = 0; i < n; i++) { dist[i] = MAX; visited[i] = false; } dist[src] = 0; for (int i = 0; i < n - 1; i++) { // 找到dist值最小的点 int u = minDistance(dist, visited); visited[u] = true; // 更新u的邻接点的dist值 for (int v = 0; v < n; v++) { if (!visited[v] && graph[u][v] != 0 && dist[u] != MAX && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; } } } // 输出最短路径 printSolution(dist); } private static int minDistance(int[] dist, boolean[] visited) { int min = MAX; int minIndex = -1; for (int v = 0; v < dist.length; v++) { if (!visited[v] && dist[v] <= min) { min = dist[v]; minIndex = v; } } return minIndex; } private static void printSolution(int[] dist) { System.out.println("Vertex \t Distance from Source"); for (int i = 0; i < dist.length; i++) { System.out.println(i + " \t\t " + dist[i]); } } public static void main(String[] args) { int[][] graph = {{0, 2, 0, 6, 0}, {2, 0, 3, 8, 5}, {0, 3, 0, 0, 7}, {6, 8, 0, 0, 9}, {0, 5, 7, 9, 0}}; dijkstra(graph, 0); } } ``` 以上代码中,我们首先定义了一个`MAX`常量表示整数的最大值。然后,我们通过`dijkstra()`方法实现Dijkstra算法。在该方法中,我们首先初始化一个`dist`数组和一个`visited`数组,分别用于存储各个节点的距离和是否已经访问过。然后,我们将起始节点的距离设为0,其余节点的距离设为`MAX`。 接下来,我们在循环中找到`dist`值最小的未访问过的节点,将其标记为已访问,并更新其邻接点的距离。在循环结束后,我们将输出最短路径,即输出各个节点距离起点的距离。 最后,我们通过`main()`方法测试了上面的代码,输出的结果为: ``` Vertex Distance from Source 0 0 1 2 2 3 3 6 4 8 ``` 这说明从节点0到各个节点的最短路径分别为0、2、3、6和8。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值