java: Prim Algorithms and Kruskal Algorithms
项目结构本文介绍了一个Java实现的物流网络最小生成树算法项目包含Prim和Kruskal两种算法的领域驱动设计实现。项目采用分层架构定义了聚合根(AggregateRoot)、实体(Entity)、值对象(IValueObject)等DDD核心元素并实现了UnionFind并查集数据结构。主要特点提供Prim算法(适用于稠密图)和Kruskal算法(适用于稀疏图)两种实现包含物流网点(LogisticsNode)和运输线路(LogisticsEdge)的领域模型演示了珠宝供应链场景的应用计算最优运输路线和最低成本输出格式化的运输路线详情和总成本 项目采用Java 21开发使用IntelliJ IDEA作为IDE支持多种数据库。/** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:52 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : AggregateRoot.java * explain : 学习 类 **/ package PrimKruskal.common; import java.util.ArrayList; import java.util.List; /** * DDD聚合根顶层抽象类 */ public abstract class AggregateRoot { private final ListObject domainEvents new ArrayList(); public ListObject getDomainEvents() { return new ArrayList(domainEvents); } public void clearDomainEvents() { domainEvents.clear(); } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:53 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : DomainException.java * explain : 学习 类 **/ package PrimKruskal.common; /** * 统一领域业务异常 */ public class DomainException extends RuntimeException { public DomainException(String message) { super(【领域异常】 message); } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:53 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : Entity.java * explain : 学习 类 **/ package PrimKruskal.common; /** * DDD实体基类唯一ID标识 */ public abstract class Entity { private final int id; protected Entity(int id) { this.id id; } public int getId() { return id; } Override public boolean equals(Object o) { if (this o) return true; if (o null || getClass() ! o.getClass()) return false; Entity entity (Entity) o; return id entity.id; } Override public int hashCode() { return id; } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:53 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : IValueObject.java * explain : 学习 类 **/ package PrimKruskal.common; /** * DDD值对象接口不可变基于属性判等 */ public interface IValueObject { boolean equals(IValueObject other); } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:54 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : UnionFind.java * explain : 学习 类 **/ package PrimKruskal.common; /** * 并查集Kruskal算法依赖带路径压缩 */ public class UnionFind { private int[] parent; public UnionFind(int size) { parent new int[size]; for (int i 0; i size; i) { parent[i] i; } } /** * 查找根节点路径压缩 */ public int find(int x) { if (parent[x] ! x) { parent[x] find(parent[x]); } return parent[x]; } /** * 合并两个集合 * return true合并成功无环false成环 */ public boolean union(int x, int y) { int rootX find(x); int rootY find(y); if (rootX rootY) { return false; } parent[rootY] rootX; return true; } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:57 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : KruskalAlgorithm.java * explain : 学习 类 **/ package PrimKruskal.domain.algorithm; import PrimKruskal.common.DomainException; import PrimKruskal.common.UnionFind; import PrimKruskal.domain.model.LogisticsEdge; import PrimKruskal.domain.model.LogisticsNode; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * Kruskal最小生成树领域算法服务 * 适用跨城分散矿区、门店【稀疏图】 */ public class KruskalAlgorithm { public static Result calculate(ListLogisticsEdge edgeList, ListLogisticsNode nodes) { int nodeCnt nodes.size(); if (nodeCnt 0) { throw new DomainException(网点集合不能为空无法生成物流路网); } // 按成本升序排序 ListLogisticsEdge sortedEdges edgeList.stream() .sorted((e1, e2) - Double.compare(e1.getCost(), e2.getCost())) .collect(Collectors.toList()); UnionFind uf new UnionFind(nodeCnt); ListLogisticsEdge mstEdges new ArrayList(); double totalCost 0D; for (LogisticsEdge edge : sortedEdges) { if (uf.union(edge.getStartId(), edge.getEndId())) { mstEdges.add(edge); totalCost edge.getCost(); if (mstEdges.size() nodeCnt - 1) { break; } } } if (mstEdges.size() ! nodeCnt - 1) { throw new DomainException(网点图不连通无法构建完整物流最小生成树); } return new Result(mstEdges, totalCost); } public static class Result { private final ListLogisticsEdge edges; private final double cost; public Result(ListLogisticsEdge edges, double cost) { this.edges edges; this.cost cost; } public ListLogisticsEdge getEdges() { return edges; } public double getCost() { return cost; } } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:56 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : PrimAlgorithm.java * explain : 学习 类 **/ package PrimKruskal.domain.algorithm; import PrimKruskal.common.DomainException; import PrimKruskal.domain.model.LogisticsEdge; import PrimKruskal.domain.model.LogisticsNode; import java.util.ArrayList; import java.util.List; /** * Prim最小生成树领域算法服务 * 适用商圈门店、加工厂密集【稠密图】 */ public class PrimAlgorithm { public static Result calculate(double[][] adjMatrix, ListLogisticsNode nodes) { int nodeCnt nodes.size(); if (nodeCnt 0) { throw new DomainException(网点集合不能为空无法生成物流路网); } final double INF Double.MAX_VALUE; boolean[] inMst new boolean[nodeCnt]; double[] minDist new double[nodeCnt]; int[] preNode new int[nodeCnt]; for (int i 0; i nodeCnt; i) { minDist[i] INF; preNode[i] -1; } minDist[0] 0; ListLogisticsEdge edgeList new ArrayList(); double totalCost 0D; for (int round 0; round nodeCnt; round) { // 选取距离生成树最近的未加入节点 int selectIdx -1; double minVal INF; for (int i 0; i nodeCnt; i) { if (!inMst[i] minDist[i] minVal) { minVal minDist[i]; selectIdx i; } } if (selectIdx -1) { throw new DomainException(网点图不连通无法构建完整物流最小生成树); } inMst[selectIdx] true; totalCost minVal; // 记录边 int preIdx preNode[selectIdx]; if (preIdx ! -1) { edgeList.add(new LogisticsEdge(preIdx, selectIdx, adjMatrix[preIdx][selectIdx])); } // 松弛更新邻接点距离 for (int j 0; j nodeCnt; j) { double weight adjMatrix[selectIdx][j]; if (!inMst[j] weight 0 weight minDist[j]) { minDist[j] weight; preNode[j] selectIdx; } } } return new Result(edgeList, totalCost); } /** 算法返回结果封装 */ public static class Result { private final ListLogisticsEdge edges; private final double cost; public Result(ListLogisticsEdge edges, double cost) { this.edges edges; this.cost cost; } public ListLogisticsEdge getEdges() { return edges; } public double getCost() { return cost; } } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:55 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : LogisticsEdge.java * explain : 学习 类 **/ package PrimKruskal.domain.model; import PrimKruskal.common.IValueObject; /** * 运输线路【值对象】 * cost综合成本路费、押运安保、保险、货品损耗单位千元 */ public class LogisticsEdge implements IValueObject { private final int startId; private final int endId; private final double cost; public LogisticsEdge(int startId, int endId, double cost) { this.startId startId; this.endId endId; this.cost cost; } public int getStartId() { return startId; } public int getEndId() { return endId; } public double getCost() { return cost; } Override public boolean equals(IValueObject other) { if (!(other instanceof LogisticsEdge)) { return false; } LogisticsEdge edge (LogisticsEdge) other; return this.startId edge.startId this.endId edge.endId Double.compare(this.cost, edge.cost) 0; } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:56 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : LogisticsMST.java * explain : 学习 类 **/ package PrimKruskal.domain.model; import PrimKruskal.common.AggregateRoot; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 最小生成树聚合根 * 聚合全部网点、MST选中线路、全网总成本 */ public class LogisticsMST extends AggregateRoot { private ListLogisticsNode allNodes new ArrayList(); private ListLogisticsEdge mstEdges new ArrayList(); private double totalCost 0D; public void setAllNodes(ListLogisticsNode allNodes) { this.allNodes allNodes; } public void setResult(ListLogisticsEdge edges, double totalCost) { this.mstEdges edges; this.totalCost totalCost; } public double getTotalCost() { return totalCost; } public ListLogisticsEdge getMstEdges() { return mstEdges; } /** * 格式化打印详情封装成 起点名、终点名、成本 */ public ListObject[] getDetailList() { MapInteger, String nodeNameMap new HashMap(); for (LogisticsNode node : allNodes) { nodeNameMap.put(node.getId(), node.getNodeName()); } ListObject[] result new ArrayList(); for (LogisticsEdge edge : mstEdges) { String sName nodeNameMap.get(edge.getStartId()); String eName nodeNameMap.get(edge.getEndId()); result.add(new Object[]{sName, eName, edge.getCost()}); } return result; } } /** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 6:54 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : LogisticsNode.java * explain : 学习 类 **/ package PrimKruskal.domain.model; import PrimKruskal.common.Entity; /** * 物流网点【实体】 * 珠宝供应链节点矿区、加工厂、仓储、线下门店 */ public class LogisticsNode extends Entity { private final String nodeName; private final String nodeCategory; public LogisticsNode(int id, String nodeName, String nodeCategory) { super(id); this.nodeName nodeName; this.nodeCategory nodeCategory; } public String getNodeName() { return nodeName; } public String getNodeCategory() { return nodeCategory; } }调用/** * encoding: utf-8 * 版权所有 2026 ©涂聚文有限公司 ® * 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 * 描述Prim Algorithms and Kruskal Algorithms 普里姆算法和克鲁斯卡尔算法 * Author : geovindu,Geovin Du 涂聚文. * IDE : IntelliJ IDEA 2024.3.6 Java 21 * # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j * # OS : window10 * Datetime : 2026 - 2026/8/8 - 7:01 * User : geovindu * Product : IntelliJ IDEA * Project : javadesginpattern * File : PrimKruskalBll.java * explain : 学习 类 **/ package Bll; import PrimKruskal.application.LogisticsRouteAppService; import PrimKruskal.domain.model.LogisticsEdge; import PrimKruskal.domain.model.LogisticsMST; import PrimKruskal.domain.model.LogisticsNode; import java.util.ArrayList; import java.util.List; public class PrimKruskalBll { /** * 示例 */ public void Demo() { // 1. 初始化珠宝供应链网点 ListLogisticsNode nodeList new ArrayList(); nodeList.add(new LogisticsNode(0, 缅甸翡翠矿区A, 原料矿区)); nodeList.add(new LogisticsNode(1, 云南分拣加工厂, 加工中心)); nodeList.add(new LogisticsNode(2, 深圳总仓储中心, 仓储中心)); nodeList.add(new LogisticsNode(3, 广州旗舰门店, 线下门店)); nodeList.add(new LogisticsNode(4, 上海门店, 线下门店)); nodeList.add(new LogisticsNode(5, 北京门店, 线下门店)); // 2. Prim邻接矩阵0无直达路线 double[][] adjMatrix { {0, 12, 28, 0, 0, 0}, {12, 0, 8, 15, 0, 0}, {28, 8, 0, 6, 18, 22}, {0, 15, 6, 0, 25, 0}, {0, 0, 18, 25, 0, 14}, {0, 0, 22, 0, 14, 0} }; // 3. Kruskal原始边集合 ListLogisticsEdge edgeList new ArrayList(); edgeList.add(new LogisticsEdge(0, 1, 12)); edgeList.add(new LogisticsEdge(0, 2, 28)); edgeList.add(new LogisticsEdge(1, 2, 8)); edgeList.add(new LogisticsEdge(1, 3, 15)); edgeList.add(new LogisticsEdge(2, 3, 6)); edgeList.add(new LogisticsEdge(2, 4, 18)); edgeList.add(new LogisticsEdge(2, 5, 22)); edgeList.add(new LogisticsEdge(3, 4, 25)); edgeList.add(new LogisticsEdge(4, 5, 14)); LogisticsRouteAppService appService new LogisticsRouteAppService(); // Prim输出 System.out.println( Prim算法-稠密网点物流规划 ); LogisticsMST primMst appService.buildByPrim(adjMatrix, nodeList); for (Object[] item : primMst.getDetailList()) { String start (String) item[0]; String end (String) item[1]; double cost (Double) item[2]; System.out.printf(%s -- %s 运输成本%.0f千元%n, start, end, cost); } System.out.printf(全网最低总成本%.0f 千元%n%n, primMst.getTotalCost()); // Kruskal输出 System.out.println( Kruskal算法-稀疏跨城网点规划 ); LogisticsMST krusMst appService.buildByKruskal(edgeList, nodeList); for (Object[] item : krusMst.getDetailList()) { String start (String) item[0]; String end (String) item[1]; double cost (Double) item[2]; System.out.printf(%s -- %s 运输成本%.0f千元%n, start, end, cost); } System.out.printf(全网最低总成本%.0f 千元%n, krusMst.getTotalCost()); } }输出