java实现Dijkstra算法


一.Dijkstra算法想解决的问题

解决的问题: 求解单源最短路径,即各个节点到达源点的最短路径或权值
在这里插入图片描述
考察其他所有节点到源点的最短路径和长度
局限性: 无法解决权值为负数的情况


二. Dijkstra算法理论

参数:

S记录当前已经处理过的源点到最短节点
U记录还未处理的节点
dist[]记录各个节点到起始节点的最短权值
path[]记录各个节点的上一级节点(用来联系该节点到起始节点的路径)

在这里插入图片描述

Dijkstra算法步骤:
(1)初始化:
顶点集S: 节点A到自已的最短路径长度为0。只包含源点,即S={A}
顶点集U: 包含除A外的其他顶点. 即U={B,C,D,E,F}
dist[]: 源点还不能到达的节点,其权值为∞

ABCDEF
dist[]:012345
初始化值:063

path[]: 记录当前节点的前驱节点下标(源点还不能到达的节点为-1)

ABCDEF
path[]:012345
初始化值:000-1-1-1

(2)从U中选取一个节点,它是源点A到U集中最短路径长度最小的节点,如上述为C然后把C加入S中(此时求出了源点A到C的最短路径长度。 S={A,C}

(3)以C为考虑的中间点,修改节点C的出边邻接点B的最短路径长度,此时源点A到节点B的最短路径有两条,即一条经过节点C,一条不经过节点C。
修改源点A到顶点B的最短路径长度=min(不经过节点C的最短路径,经过节点C的最短路径)

在这里插入图片描述

以此方法求出各个节点到源点的最短路径:
在这里插入图片描述

第一次探索

s={A,C}
U={B,D,E,F}
ABCDEF
dist[]:012345
0min(A->B,A->C->B)=5367
ABCDEF
path[]:012345
02022-1

U集中dist 值 min(5,6,7,∞)=5 ,因此B加入到S集
第二次探索
在这里插入图片描述

s={A,B,C}
U={D,E,F}
ABCDEF
dist[]:012345
053min(6,11)=67
ABCDEF
path[]:012345
02022-1

U集中dist 值 min(6,7,∞)=6 ,因此D加入到S集

第三次探索
在这里插入图片描述

s={A,B,C,D}
U={E,F}
ABCDEF
dist[]:012345
0536min(7,8)=79
ABCDEF
path[]:012345
020223

U集中dist 值 min(7,9)=6 ,因此F加入到S集

第四次探索
在这里插入图片描述

s={A,B,C,D,F}
U={E}
ABCDEF
dist[]:012345
0536min(7,9+5)=79
ABCDEF
path[]:012345
020223

U集中dist 值 min(E)=7 ,因此E加入到S集

最终结果: 源点到达各点的最短路径为dist数组中的值
s={A,B,C,D,E,F}
u={}

ABCDEF
dist[]:012345
053679
ABCDEF
path[]:012345
020223

三. java代码实现

GitHub源代码地址: https://github.com/yuanjiejiahui/Dijkstra

在这里插入图片描述

核心代码:

 public void dijkstra(V v0, V vi) {
        // 从顶点vO出发,查找到vi的最短路径

        // listU 记录还未处理的节点
        ArrayList<Integer> listU = new ArrayList<>();
        // dist[] 记录各个节点到起始节点的最短权值
        int[] dist = new int[this.vertices];
        // 记录各个节点的上一级节点(用来联系该节点到起始节点的路径)
        int[] path = new int[this.vertices];

        int start = this.vertexList.indexOf(v0); // 源点序号
        int end = this.vertexList.indexOf(vi); // 结束顶点序号

        // 初始化U集合
        for (int i = 0; i < this.vertices; i++) {
            if (i == start) { // S={start}
                continue;
            }
            listU.add(i); // u={vi}/{start}
        }
        // 初始化dist[],path[]
        for (int i = 0; i < this.vertices; i++) {
            // dist[]的当前节点权值就等于start->i节点的权值;初始化所有节点到源点的最短距离
            dist[i] = this.edgeMatrix[start][i];
            if (this.edgeMatrix[start][i] == Integer.MAX_VALUE) {
                path[i] = -1; // 节点i不可达
            } else {
                path[i] = start; // 若start能直达某点,则表示节点i可以直接访问到start;
            }
        }

        // 记录最小值的节点序号
        int minIndex;
        // int minIndexByI=0;
        do {
            System.out.println("集合U的状态: " + listU);
            // dist数组下标
            minIndex = listU.get(0);
            for (int i = 1; i < listU.size(); i++) {
                if (dist[listU.get(i)] < dist[minIndex]) {
                    minIndex = listU.get(i);
                    // minIndexByI = i;
                }
            }
            listU.remove((Integer) minIndex);
            // listU.remove(minIndexByI);

            // 更新dist和path数组,主要考察minIndex节点纳入S,即新加入节点最短路径变化.
            for (int i = 0; i < this.vertices; i++) {
                if (this.edgeMatrix[minIndex][i] != 0 && this.edgeMatrix[minIndex][i] < Integer.MAX_VALUE) {
                    // 找到minIndex的所有邻接点
                    if (this.edgeMatrix[minIndex][i] + dist[minIndex] < dist[i]) {
                        // 新加入节点更短
                        dist[i] = this.edgeMatrix[minIndex][i] + dist[minIndex];
                        path[i] = minIndex;
                    }
                }
            }
        } while (minIndex != end && !listU.isEmpty());

        System.out.println("节点" + v0 + "=>" + vi + "最短路径是: " + dist[end]);
        String str = "" + vi;
        int i = end;
        do {
            i = path[i];
            str = this.vertexList.get(i) + "=>" + str;
        } while (i != start);
        System.out.println(str);
    }
  • 15
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Dijkstra算法是用于解决单源最短路径问题的一种高效算法,特别是在有向无环图(DAG)或带权重的边的图中。在Java实现Dijkstra算法,你可以使用优先队列(通常使用`java.util.PriorityQueue`)来存储尚未确定最短路径的节点,以及一个哈希映射或邻接表来存储图的结构。 以下是Java实现Dijkstra算法的一个基本步骤: 1. 初始化:创建一个HashMap或类似的数据结构,将起点的距离设为0,其他所有节点的距离设为无穷大,同时标记为未访问。 2. 创建优先队列:将起点放入队列,并设置其优先级为起点距离。 3. 主循环:从队列中取出当前距离最小的节点(通常是最小优先级的节点),然后更新其相邻节点的距离,如果通过当前节点到达更短,就更新这些节点的距离并将它们加入队列。 4. 遍历邻接节点:对于每个相邻节点,检查通过当前节点到达它的路径是否比之前记录的更短。如果是,更新并标记该节点为已访问。 5. 重复步骤3和4,直到队列为空或找到终点。如果队列为空且未访问到终点,说明找不到从起点到终点的路径。 ```java import java.util.*; class Node implements Comparable<Node> { int id; int distance; Node previous; public Node(int id) { this.id = id; this.distance = Integer.MAX_VALUE; } @Override public int compareTo(Node other) { return Integer.compare(this.distance, other.distance); } } public class Dijkstra { // 使用PriorityQueue存储节点 private PriorityQueue<Node> queue = new PriorityQueue<>(); // 图的邻接表或哈希映射 private Map<Integer, List<Node>> graph; public List<Node> dijkstra(int start) { // ... (初始化、添加起点到队列等) while (!queue.isEmpty()) { Node current = queue.poll(); // 取出距离最小的节点 // 更新未访问的邻居 for (Node neighbor : graph.get(current.id)) { int distanceToNeighbor = current.distance + neighbor.distance; if (distanceToNeighbor < neighbor.distance) { neighbor.distance = distanceToNeighbor; neighbor.previous = current; queue.offer(neighbor); } } } // 返回从起点到终点的路径,如果找到 return buildPath(start); } private List<Node> buildPath(int end) { List<Node> path = new ArrayList<>(); Node currentNode = endNode(end); while (currentNode != null) { path.add(currentNode); currentNode = currentNode.previous; } Collections.reverse(path); return path; } // ... (获取结束节点的方法,可能需要一个额外的哈希映射存储每个节点的结束标识) } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最难不过坚持丶渊洁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值