Java最小生成树

        最小生成树,指的是对于一个无向图,使得点连通的最小权值和的边集,就是最小生成树。

最小生成树的计算有两种经典的算法:Kruskal算法、Prim算法。

        Kruskal算法:从边的角度考虑,边权重从小到大排序,依次考虑每条边加入是否形成环,形成环,则不要该条边;否则要该条边。

        难点:如何判断加入一条边的时候是否形成环?需要利用并查集。如果当前边的两个节点在一个集合里,说明之前已经有边使得这两个点连通了,所以就不能再加入当前边。

        Prim算法:从点的角度出发,任选一个点出发,当选择了该点时,其对应的边也都解锁了,从解锁的边里选择权重最小的边,判断该边的另一个点是否已经加过,没有加过,就加入该点,并将该点对应的边都解锁。然后从所有解锁的边里,找最小的边,循环上面的过程,直到所有点都被加入。

public Set<GraphEdge> KruskalMST(Graph graph){
    Set<GraphEdge> res=new HashSet();
    //初始化并查集,这里是一个简单的实现,后续写并查集的优雅实现查找和合并都是O(1)
    MyUnionSet unionSet = new MyUnionSet((new ArrayList<>(graph.nodes.values()));
    List<GraphEdge> edges=graph.edges;
    edges.sort(o1,o2->(o1-o2));
    for(GraphEdge edge:edges){
        if(!isSameSet(edge.from,edge.to)){
            res.add(edge);
            union(edge.from,edge.to);
        }
    }
    return res;
}     
public Set<GraphEdge> PrimMST(Graph graph) {
       Set<GraphEdge> res = new HashSet<>();
       Set<GraphNode> set = new HashSet<>();
       PriorityQueue<GraphEdge> heap = new PriorityQueue<>((o1, o2) -> o1.weight - o2.weight);
       //for循环是为了解决森林的问题
       for (GraphNode node : graph.nodes.values()) {
           if (!set.contains(node)) {
               set.add(node);
               heap.addAll(node.edges);
           }
           while (!heap.isEmpty()) {
               GraphEdge edge = heap.poll();
               if (!set.contains(edge.to)) {
                   res.add(edge);
                   set.add(edge.to);
                   heap.addAll(edge.to.edges);
               }
           }
       }
       return res;
   }
//简单的并查集实现
public class MyUnionSet {

    public Map<GraphNode, List<GraphNode>> setMap;

    public MyUnionSet(List<GraphNode> nodes) {
        setMap = new HashMap<>();
        for (GraphNode node : nodes) {
            setMap.put(node, new ArrayList<>(nodes));
        }
    }

    public boolean isSameSet(GraphNode node1, GraphNode node2) {
        List<GraphNode> list1 = setMap.get(node1);
        List<GraphNode> list2 = setMap.get(node2);
        return list1 == list2;
    }

    public void union(GraphNode node1, GraphNode node2) {
        if (!isSameSet(node1, node2)) {
            List<GraphNode> list1 = setMap.get(node1);
            List<GraphNode> list2 = setMap.get(node2);
            for (GraphNode node : list2) {
                list1.add(node);
                setMap.put(node, list1);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值