Java实现单源最短路径算法(Dijkstra 算法)
参考:《算法导论》
@Data @AllArgsConstructor public class WeightGraph { //节点名,前驱节点,最短路径 private List<Node<String,String,Integer>> nodes; //节点名,连接节点索引,边权重 private Table<String, Integer, Integer> edgeTable; public static void main(String[] args) { //构建图 WeightGraph graph = buildGraph(); List<Node<String, String, Integer>> nodes = graph.getNodes(); Table<String, Integer, Integer> edgeTable = graph.getEdgeTable(); //已知最短路径的节点集合S HashSet<String> S = new HashSet<>(); //优先队列,以最短路径为排序key Queue<Node<String,String, Integer>> queue = new PriorityQueue<>(Comparator.comparing(Node::getDistance)); //节点信息的初始化,v1=0,其他未知都是无穷大 nodes.forEach(node->{ if (node.getName().equals("v1")) { node.setDistance(0); } }); //队列初始化,将所有节点加入队列 queue.addAll(nodes); while (!queue.isEmpty()) { //第一个获取的就是v1 Node<String,String, Integer> nodeU = queue.remove(); String nodeUName = nodeU.getName(); S.add(nodeUName); Map<Integer, Integer> row = edgeTable.row(nodeUName); //对u->v节点进行松弛操作 //如果v.d大于u.d+w(u,v),则将更小的值更新为v.d for (Map.Entry<Integer, Integer> entry : row.entrySet()) { Integer nodeVIndex = entry.getKey(); Node<String, String, Integer> nodeV = nodes.get(nodeVIndex); Integer weightUV = entry.getValue(); if (nodeV.getDistance() > nodeU.getDistance() + weightUV) { nodeV.setDistance(nodeU.getDistance() + weightUV); nodeV.setPre(nodeUName); } } } for (Node<String, String, Integer> node : nodes) { System.out.println(node.getName()+":"+node.getDistance()); } System.out.println(S); } /** * 初始化图结构 * * @return */ public static WeightGraph buildGraph() { List<String> nodes = Lists.newArrayList("v1", "v2", "v3", "v4", "v5", "v6"); List<Node<String, String, Integer>> nodeList = nodes.stream().map(node -> { Node<String, String, Integer> nodeObj = new Node<>(); nodeObj.setName(node); nodeObj.setPre(null); nodeObj.setDistance(Integer.MAX_VALUE); return nodeObj; }).collect(Collectors.toList()); Table<String, Integer, Integer> edgeTable = HashBasedTable.create(); edgeTable.put("v1", nodes.indexOf("v2"), 10); edgeTable.put("v2", nodes.indexOf("v3"), 7); edgeTable.put("v4", nodes.indexOf("v3"), 4); edgeTable.put("v4", nodes.indexOf("v5"), 7); edgeTable.put("v6", nodes.indexOf("v5"), 1); edgeTable.put("v1", nodes.indexOf("v6"), 3); edgeTable.put("v6", nodes.indexOf("v2"), 2); edgeTable.put("v4", nodes.indexOf("v1"), 3); edgeTable.put("v2", nodes.indexOf("v4"), 5); edgeTable.put("v6", nodes.indexOf("v4"), 6); return new WeightGraph(nodeList,edgeTable); } /** * 节点名,前驱节点,最短路径 * 也用于存储最终的最短路径数据 * * @param <N> * @param <D> */ @Data @AllArgsConstructor @NoArgsConstructor static class Node<N,P, D> { private N name; private P pre; private D distance; } }
输出:
v1:0 v2:5 v3:12 v4:9 v5:4 v6:3
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗