Java实现最短路径算法(Dijkstra 算法)
参考:
https://zhuanlan.zhihu.com/p/129373740
《数据结构与算法-python描述》作者:裘宗燕
以上是原图,求V1到其余所有节点的最短路径。参考了裘宗燕教授的数据结构与算法
并未完全理解其精髓,暂且记录,后面再慢慢理解
@Data @AllArgsConstructor public class WeightGraph { private List<String> nodes; private List<WeightEdge<String, String, Integer>> edgeList; public static void main(String[] args) { WeightGraph weightGraph = buildGraph(); Map<String, Path<String, Integer>> shortest = findShortest(weightGraph); for (Map.Entry<String, Path<String, Integer>> entry : shortest.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue().getLen()); } } /** * 初始化图结构 * * @return */ public static WeightGraph buildGraph() { List<String> node = Lists.newArrayList("v1", "v2", "v3", "v4", "v5", "v6"); List<WeightEdge<String, String, Integer>> edge = Lists.newArrayList(); edge.add(new WeightEdge<>("v1", "v2", 10)); edge.add(new WeightEdge<>("v2", "v3", 7)); edge.add(new WeightEdge<>("v4", "v3", 4)); edge.add(new WeightEdge<>("v4", "v5", 7)); edge.add(new WeightEdge<>("v6", "v5", 1)); edge.add(new WeightEdge<>("v1", "v6", 3)); edge.add(new WeightEdge<>("v6", "v2", 2)); edge.add(new WeightEdge<>("v4", "v1", 3)); edge.add(new WeightEdge<>("v2", "v4", 5)); edge.add(new WeightEdge<>("v6", "v4", 6)); return new WeightGraph(node, edge); } public static Map<String, Path<String, Integer>> findShortest(WeightGraph weightGraph) { List<WeightEdge<String, String, Integer>> edgeList = weightGraph.getEdgeList(); List<String> nodes = weightGraph.getNodes(); //以路径边长做key的优先级队列 PriorityQueue<Triple<Integer, String, String>> queue = new PriorityQueue<>(Comparator.comparing(Triple::getLen)); //初始化队列 //表示原点v1,经中间节点v1,到v1的距离是0 queue.add(new Triple<>(0, "v1", "v1")); //结果map Map<String, Path<String, Integer>> paths = new HashMap<>(); //paths初始为null,用于存储最终结果 int size = nodes.size(); for (String node : nodes) { paths.put(node, null); } int count = 0; while (count < size && !queue.isEmpty()) { //长度、中介、终点 Triple<Integer, String, String> triple = queue.remove(); String end = triple.getEnd(); //如果end已经找到,则跳过本次循环 if (paths.get(end) != null) { continue; } //如果end还为找到最短路径 Integer len = triple.getLen(); //因为从优先队列头部取出,因此<end,len>就是当前已知的最短路径 //第一次执行("v1",new Path("v1",0)),v1经v1到v1的最短距离是0 paths.put(end, new Path<>(triple.getMiddle(), len)); //遍历所有以新得到的最短路径节点做start的边,扩展可达的边界 for (WeightEdge<String, String, Integer> edge : edgeList) { if (edge.getStart().equals(end)) { String newEnd = edge.getEnd(); Integer w = edge.getWeight(); //如果新目标还未确定最短路径,则将end做中介,原end的len+weight作为新的len,并加入优先queue //优先队列保证经过这轮循环,得到了最新的最短路径节点 if (paths.get(newEnd) == null) { queue.add(new Triple<>(len + w, end, newEnd)); } } } count += 1; } return paths; } } /** * 带权重的边 * * @param <S> * @param <E> * @param <W> */ @Data @AllArgsConstructor @NoArgsConstructor class WeightEdge<S, E, W> { private S start; private E end; private W weight; } /** * 优先队列元素三元组,主要用于获取目标节点的最短路径 * * @param <L> length * @param <M> 中介点 * @param <E> 目标点 */ @Data @AllArgsConstructor class Triple<L, M, E> { private L len; private M middle; private E end; } /** * paths的元素格式 * * @param <M> 中介点 * @param <L> 最终最短路径 */ @Data @AllArgsConstructor class Path<M, L> { private M middle; private L len; }
输出:
v6:3 v1:0 v2:5 v3:12 v4:9 v5:4
【推荐】国内首个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,是通过提示词来发起调用的吗