克鲁斯卡尔算法(并查集)

最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。

Kruskal 算法使用了贪心的思想:将所有的边按照权重从小到大进行排序,然后从权重最小的边开始遍历,如果这条边和结果集中的边(已经加入到最小生成树中的边)不会形成环,那么这条边就是最小生成树的一部分,将它加入到结果集中;否则,这条边就不是最小生成树的一部分,就不要把它加入到结果集中

import java.util.Arrays;
import java.util.Comparator;

public class MyKruskal {
    public static final int N = 100000;// 用10000表示两个结点之间不能连接,或者也可以用Integer.MAX_VALUE

    public static void main(String[] args) {
        int[][] map = {
                {N, 12, N, N, N, 16, 14},
                {12, N, 10, N, N, 7, N},
                {N, 10, N, 3, 5, 6, N},
                {N, N, 3, N, 4, N, N},
                {N, N, 5, 4, N, 2, 8},
                {16, 7, 6, N, 2, N, 9},
                {14, N, N, N, 8, 9, N}
        };
        kruskal(map);
    }
    /* kruskal 算法的思路:将所有的边按照权重从小到大进行排序,然后从权重最小的边开始遍历,如果这条边和结果集中的边(已经加入到最小生成树中的边)不会形成环,那么这条边就是最小生成树的一部分,将它加入到结果集中;否则,这条边就不是最小生成树的一部分,就不要把它加入到结果集中 */
    public static void kruskal(int[][] map) {
        int numOfVertex = map.length;// 结点的数量
        int numOfEdge = 0;// 边的数量
        for (int i = 0; i < numOfVertex; i++) {
            for (int j = i + 1; j < numOfVertex; j++) {
                if (map[i][j] != N) {
                    numOfEdge++;
                }
            }
        }
        // 根据邻接矩阵得到边集数组
        Edge[] edges = new Edge[numOfEdge];
        int index = 0;
        for (int i = 0; i < numOfVertex; i++) {
            for (int j = i + 1; j < numOfVertex; j++) {
                if (map[i][j] != N) {
                    edges[index++] = new Edge(i, j, map[i][j]);
                }
            }
        }
        // 对边集数组进行排序
        Arrays.sort(edges, new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        
        UF uf = new UF(numOfVertex);
        for (int i = 0; i < numOfEdge; i++) {
            if (uf.union(edges[i].from, edges[i].to)) {
                System.out.println("<" + "from = " + edges[i].from + ", to = " + edges[i].to + ">的权值是:" + edges[i].weight);
            }
        }
    }
}

class Edge {
    int from;// 边的起始顶点
    int to;// 边的终止顶点
    int weight;// 边的权值

    public Edge(int from, int to, int weight) {
        this.from = from;
        this.to = to;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Edge{" + "from=" + from + ", to=" + to + ", weight=" + weight + '}';
    }
}

// 并查集用于确保生成的东西是树(树是不包括环的)
class UF {
    int[] parent;
    int[] size;

    public UF(int n) {
        parent = new int[n];
        size = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
            size[i] = 1;
        }
    }

    public int find(int x) {
        while (x != parent[x]) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    public boolean union(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);
        if (rootP == rootQ) {
            return false;
        }
        if (size[rootP] > size[rootQ]) {
            parent[rootQ] = rootP;
            size[rootP] += size[rootQ];
        } else {
            parent[rootP] = rootQ;
            size[rootQ] += size[rootP];
        }
        return true;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静波波呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值