java: Prim Algorithms and Kruskal Algorithms

项目结构:

image

 

/**
 * 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 List<Object> domainEvents = new ArrayList<>();

    public List<Object> 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(List<LogisticsEdge> edgeList, List<LogisticsNode> nodes) {
        int nodeCnt = nodes.size();
        if (nodeCnt <= 0) {
            throw new DomainException("网点集合不能为空,无法生成物流路网");
        }
        // 按成本升序排序
        List<LogisticsEdge> sortedEdges = edgeList.stream()
                .sorted((e1, e2) -> Double.compare(e1.getCost(), e2.getCost()))
                .collect(Collectors.toList());

        UnionFind uf = new UnionFind(nodeCnt);
        List<LogisticsEdge> 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 List<LogisticsEdge> edges;
        private final double cost;

        public Result(List<LogisticsEdge> edges, double cost) {
            this.edges = edges;
            this.cost = cost;
        }

        public List<LogisticsEdge> 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, List<LogisticsNode> 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;

        List<LogisticsEdge> 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 List<LogisticsEdge> edges;
        private final double cost;

        public Result(List<LogisticsEdge> edges, double cost) {
            this.edges = edges;
            this.cost = cost;
        }

        public List<LogisticsEdge> 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 List<LogisticsNode> allNodes = new ArrayList<>();
    private List<LogisticsEdge> mstEdges = new ArrayList<>();
    private double totalCost = 0D;

    public void setAllNodes(List<LogisticsNode> allNodes) {
        this.allNodes = allNodes;
    }

    public void setResult(List<LogisticsEdge> edges, double totalCost) {
        this.mstEdges = edges;
        this.totalCost = totalCost;
    }

    public double getTotalCost() {
        return totalCost;
    }

    public List<LogisticsEdge> getMstEdges() {
        return mstEdges;
    }

    /**
     * 格式化打印详情,封装成 起点名、终点名、成本
     */
    public List<Object[]> getDetailList() {
        Map<Integer, String> nodeNameMap = new HashMap<>();
        for (LogisticsNode node : allNodes) {
            nodeNameMap.put(node.getId(), node.getNodeName());
        }
        List<Object[]> 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. 初始化珠宝供应链网点
        List<LogisticsNode> 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原始边集合
        List<LogisticsEdge> 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());

    }
}

  

 

posted @ 2026-08-08 07:12  ®Geovin Du Dream Park™  阅读(4)  评论(0)    收藏  举报