union-find问题

union-find算法实现

union-find问题就是动态图连通性问题,即图中两点是否连通。

加权quick-union算法

加权quick-union算法是解决union-find问题比较高效的办法,主要思想为:

同一连接分量的节点使用树进行连接,find()函数可以查找节点所在连接分量树的根节点,通过比较根节点是否相同来判断节点是否属于同一连通分量。

连接时如果两节点不在同一连通分量上则需要将两个连通分量并到同一棵树上,此处便是加权的思想:将节点数较小的树的根节点连接到节点数较大的根节点上,这样可使树的深度尽量降低。

具体算法如下:

import java.util.Random;

/**
 * 加权quick-union算法
 * union函数连接节点
 * connected函数判断节点是否连通
 * <p>
 * 对于n个节点,m条连接最多访问数组cMlgN次
 *
 * @author zhkp
 */
public class WeightedQuickUnionUF {
    private int[] id; // 链接数组
    private int[] sz; // 各个节点所对应树的大小
    private int count; // 连通分量的数量

    public WeightedQuickUnionUF(int N) {
        count = N;
        id = new int[N];
        sz = new int[N];

        for (int i = 0; i < N; i++) {
            id[i] = i;
            sz[i] = 1;
        }
    }

    /**
     * @return 连通分量数量
     */
    public int count() {
        return count;
    }

    /**
     * @param p 节点p
     * @param q 节点q
     * @return 节点p、q是否连通
     */
    public boolean connected(int p, int q) {
        return find(p) == find(q);
    }

    /**
     * @param p 查询节点
     * @return 查询节点对应根节点
     */
    public int find(int p) {
        while (p != id[p]) {
            p = id[p];
        }
        return p;
    }

    public void union(int p, int q) {
        int i = find(p);
        int j = find(q);

        // 若不连通则将数量较小的树连接到数量较大的树上
        if (i == j) {
            return;
        } else if (sz[i] > sz[j]) {
            id[j] = i;
            sz[i] += sz[j];
        } else {
            id[i] = j;
            sz[j] += sz[i];
        }

        count--;
    }

    /**
    * 测试样例
    */
    public static void main(String[] args) {
        int nodeNum = 10;
        int edgeNum = 10;
        Random random = new Random();
        WeightedQuickUnionUF w = new WeightedQuickUnionUF(nodeNum);
        int a, b;
        for (int i = 0; i < edgeNum; i++) {
            a = random.nextInt(nodeNum);
            b = random.nextInt(nodeNum);

            w.union(a, b);
            System.out.println(a + " - " + b);
        }
        a = random.nextInt(nodeNum);
        b = random.nextInt(nodeNum);

        System.out.println(a + "与" + b + (w.connected(a, b) ? "已" : "不") + "连通");
        System.out.println("连通分量数量:" + w.count());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值