Java实现Dijkstra算法

本文介绍了一种使用Java实现Dijkstra算法的方法,通过定义Node、Edge、Graph和Dijkstra类来构造图并找到从指定起点到其他各点的最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dijkstra算法:用于计算图中某一点到其他各点的最短路径。关于Dijkstra算法的说明可以参考 数据结构相关书籍。

为Dijkstra算法设计的类:
1. Node        节点类

2. Edge        边类
3. Graph       图类
4. Dijkstra     Dijkstra算法类
---------------------------------------------------------------------------------------------------------------------------------
Node类:
package com.sabrina.dijkstra;

import java.util.ArrayList;
import java.util.List;

public class Node {

    // 节点编号
    private String id;
    // 从当前节点出发的边的信息列表
    private List outEdges;
   
    public Node(String id) {
        this.id = id;
        outEdges = new ArrayList();
    }
   
    public void addOutEdge(Edge edge) {
        if(edge != null)
            outEdges.add(edge);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List getOutEdges() {
        return outEdges;
    }

    public void setOutEdges(List outEdges) {
        this.outEdges = outEdges;
    }
}
 
Edge类:
package com.sabrina.dijkstra;

public class Edge {

    // 边的起始节点编号
    private String startNodeID;
    // 边的末尾节点编号
    private String endNodeID;
    // 边的权值
    private double weight;
   
    public String getStartNodeID() {
        return startNodeID;
    }
    public void setStartNodeID(String startNodeID) {
        this.startNodeID = startNodeID;
    }
    public String getEndNodeID() {
        return endNodeID;
    }
    public void setEndNodeID(String endNodeID) {
        this.endNodeID = endNodeID;
    }
    public double getWeight() {
        return weight;
    }
    public void setWeight(double weight) {
        this.weight = weight;
    }
}
 
Graph类:


 
package com.sabrina.dijkstra;

import java.util.ArrayList;
import java.util.List;

public class Graph {

    // 图中的节点列表
    public List nodeList = null;

    public Graph() {
        nodeList = new ArrayList();
    }

    public List getNodeList() {
        return nodeList;
    }

    // initialize
    public void init() {
        // ************************ Node A ***********************
        Node aNode = new Node("A");
        nodeList.add(aNode);
        // A -> B
        Edge a2bEdge = new Edge();
        a2bEdge.setStartNodeID(aNode.getId());
        a2bEdge.setEndNodeID("B");
        a2bEdge.setWeight(10);
        aNode.addOutEdge(a2bEdge);
        // A -> C
        Edge a2cEdge = new Edge();
        a2cEdge.setStartNodeID(aNode.getId());
        a2cEdge.setEndNodeID("C");
        a2cEdge.setWeight(20);
        aNode.addOutEdge(a2cEdge);
        // A -> E
        Edge a2eEdge = new Edge();
        a2eEdge.setStartNodeID(aNode.getId());
        a2eEdge.setEndNodeID("E");
        a2eEdge.setWeight(30);
        aNode.addOutEdge(a2eEdge);

        // ************************ Node B ***********************
        Node bNode = new Node("B");
        nodeList.add(bNode);
        // B -> C
        Edge b2cEdge = new Edge();
        b2cEdge.setStartNodeID(bNode.getId());
        b2cEdge.setEndNodeID("C");
        b2cEdge.setWeight(5);
        bNode.addOutEdge(b2cEdge);
        // B -> E
        Edge b2eEdge = new Edge();
        b2eEdge.setStartNodeID(bNode.getId());
        b2eEdge.setEndNodeID("E");
        b2eEdge.setWeight(10);
        bNode.addOutEdge(b2eEdge);

        // ************************ Node C ***********************
        Node cNode = new Node("C");
        nodeList.add(cNode);
        // C -> D
        Edge c2dEdge = new Edge();
        c2dEdge.setStartNodeID(cNode.getId());
        c2dEdge.setEndNodeID("D");
        c2dEdge.setWeight(30);
        cNode.addOutEdge(c2dEdge);
       
        // ************************ Node D ***********************
        Node dNode = new Node("D");
        nodeList.add(dNode);
       
        // ************************ Node E ***********************
        Node eNode = new Node("E");
        nodeList.add(eNode);
        // E -> D
        Edge e2dEdge = new Edge();
        e2dEdge.setStartNodeID(eNode.getId());
        e2dEdge.setEndNodeID("D");
        e2dEdge.setWeight(20);
        eNode.addOutEdge(e2dEdge);
       
    }
}
 
Dijkstra类:
package com.sabrina.dijkstra;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Dijkstra {

    // 起始节点编号
    private String startNodeID;
    // 未被处理的节点集合
    private List sourceNodeIDList = null;
    // 已被处理的节点集合
    private List desNodeIDList = null;

    // '节点编号' 和  '起始节点与当前节点之间的最短路径' 的映射关系
    private Map nodeidShortestRouteMapping = null;
    // '节点编号' 和  '起始节点到当前节点之间的最短路径 的 上一跳节点编号' 的映射关系
    private Map nodeidLastNodeidMapping = null;
    // '节点编号' 和  '节点对象'的 映射关系
    private Map idNodeMapping = null;
   
    public Dijkstra(Graph graph, String startNodeID) {
        this.startNodeID = startNodeID;
       
        // 初始化
        sourceNodeIDList = new ArrayList();
        desNodeIDList = new ArrayList();
        nodeidShortestRouteMapping = new HashMap();
        nodeidLastNodeidMapping = new HashMap();
        idNodeMapping = new HashMap();
       
        for(Node node : graph.getNodeList()) {
            if(node.getId().equals(startNodeID)) {
                desNodeIDList.add(startNodeID);
                // 起始节点到起始节点的最短路径长度为0
                nodeidShortestRouteMapping.put(startNodeID, 0d);
            }
            else {
                sourceNodeIDList.add(node.getId());
                // 非起始节点到起始节点的最短路径长度为 '无穷大'
                nodeidShortestRouteMapping.put(node.getId(), Double.MAX_VALUE);
            }
            // 设置到节点最短路径的上一跳节点为'null'
            nodeidLastNodeidMapping.put(node.getId(), null);
            idNodeMapping.put(node.getId(), node);
        }
    }
   
    public void start() {
        Node nextNode = null;
        Node currentNode = null;
        String nextNodeID = "";
        do {
            if(nextNode == null) {
                currentNode = idNodeMapping.get(startNodeID);
            }
            else {
                currentNode = nextNode;
            }
            nextNodeID = getNextNode(currentNode);
           
            nextNode = idNodeMapping.get(nextNodeID);
            System.out.println("nextNode.id:" + nextNode.getId());
           
            sourceNodeIDList.remove(nextNode.getId());
            System.out.println("sourceNodeIDList:" + sourceNodeIDList.toString());
        } while(sourceNodeIDList.size() > 0);
    }
   
   
    public String getNextNode(Node currentNode) {
        System.out.println("============= currentNode.id: " + currentNode.getId() + " =============");
        double shortestPath = Double.MAX_VALUE;
        String nextNodeID = "";
        //  遍历从当前节点出发的邻接节点
        for(Edge nextEdge : currentNode.getOutEdges()) {
            System.out.println("nextEdge.endNodeid:" + nextEdge.getEndNodeID());
            // 判断 '经过当前节点至邻接节点的距离' < '之前记录的从源节点出发到邻接节点的距离'
            if((nextEdge.getWeight() + nodeidShortestRouteMapping.get(currentNode.getId()))
                    < nodeidShortestRouteMapping.get(nextEdge.getEndNodeID())) {
                // 更新路由表
                nodeidShortestRouteMapping.put(nextEdge.getEndNodeID(),
                        nextEdge.getWeight() + nodeidShortestRouteMapping.get(currentNode.getId()));
                nodeidLastNodeidMapping.put(nextEdge.getEndNodeID(),
                        currentNode.getId());
            }
        }
        // 从未被处理过的节点集合中,取出权值最小的节点
        for(String nodeID : sourceNodeIDList) {
            if(nodeidShortestRouteMapping.get(nodeID) < shortestPath) {
                shortestPath = nodeidShortestRouteMapping.get(nodeID);
                nextNodeID = nodeID;
            }
        }
        if(sourceNodeIDList.size() == 1) // 从未被处理过的节点集合中,取出最后一个节点
            return sourceNodeIDList.get(0);
        return nextNodeID;
    }
   
   
    public Map getNodeidShortestRouteMapping() {
        return nodeidShortestRouteMapping;
    }

    public Map getNodeidLastNodeidMapping() {
        return nodeidLastNodeidMapping;
    }

    public static void main(String[] args) {
        Graph graph = new Graph();
        graph.init();
       
        Dijkstra dijkstra = new Dijkstra(graph, "A");
        dijkstra.start();

        // 打印最终的路由表
        Iterator it = dijkstra.getNodeidShortestRouteMapping().keySet().iterator();
        while(it.hasNext()) {
            String id = it.next();
            System.out.println("nodeId: "  + id + ", shortest length: " + dijkstra.getNodeidShortestRouteMapping().get(id)
                    + ", last nodeId: " + dijkstra.getNodeidLastNodeidMapping().get(id));
        }
    }
}
 
最终执行结果
============= currentNode.id: A =============
nextEdge.endNodeid:B
nextEdge.endNodeid:C
nextEdge.endNodeid:E
nextNode.id:B
sourceNodeIDList:[C, D, E]
============= currentNode.id: B =============
nextEdge.endNodeid:C
nextEdge.endNodeid:E
nextNode.id:C
sourceNodeIDList:[D, E]
============= currentNode.id: C =============
nextEdge.endNodeid:D
nextNode.id:E
sourceNodeIDList:[D]
============= currentNode.id: E =============
nextEdge.endNodeid:D
nextNode.id:D
sourceNodeIDList:[]
nodeId: D, shortest length: 40.0, last nodeId: E
nodeId: E, shortest length: 20.0, last nodeId: B
nodeId: A, shortest length: 0.0, last nodeId: null
nodeId: B, shortest length: 10.0, last nodeId: A
nodeId: C, shortest length: 15.0, last nodeId: B
PS:如有写的不对的,敬请纠正~
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; } // ... (获取结束节点的方法,可能需要一个额外的哈希映射存储每个节点的结束标识) } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值