Union Find算法

Union Find 算法介绍

Union Find 是一个很强大的算法,能解决动态联通性的一类问题。主要操作是find 和union。通过指定的两个点之间的关系合并这两个点,使他们属于一个组织。这样随着不断输入边,相互独立的组织会越来越少。整个图的连通性越来越强。
Find()操作也就是查找给定的点属于哪个组织,union()操作是将两个点合并到一个组织,包括这两个点所属组织的所有点都合并在一起。
底层数据结构:用id[n] 记录节点所属的组织,这样 find()操作很简单只要返回 id[i]即可,但是这样会带来缺陷,在union的时候要将所有属于i的点的id[i]全都设置成id[j],这需要扫描整个id[n]。怎么解决呢,我们可以把id[n]看做树状结构,id[i]表示i的父节点,id[id[i]]表示id[i]的父节点,当到达根节点时id[i] = i,这样在find()的时候只要找到 id[i] = i返回i即可,合并的时候只要将i的根节点父指针指向j节点即可。但是,我们进一步思考,由于在合并两个树的时候,我们没有考虑该将哪颗树挂到哪棵树上,这样势必可能会使合并的时候大树挂在小树上从而使树的高度增加,这样对后来的查找性能会产生很大的影响。如何解决呢?我们可以考虑给树设置权重,分配rank[n]来表示权重,在union的时候,将rank小的节点挂到rank大的结点上。这样find性能得到了改进。能不能更进一步改进呢?还是可以的,我们可以考虑压缩路径,在find()的时候,将i节点的父指针指向它的爷爷节点,这样在find的过程中,整个树的高度越来越短,从而让find()的效率接近O(1)。下面是完整的Union Find代码:

class UF{
    public int count;
    public int[] id;
    public int[] rank;
    public UF(int n){
        count = n;
        id = new int[n];
        rank = new int[n];
        for(int i = 0; i < n; i++){
            id[i] = i;
            rank[i] = 1;
        }
    }
    public int find(int p){
        if(id[p] != p) id[p] = find(id[p]);
        return id[p];
    }
    public void union(int p, int q){
        int pp = find(p);
        int qq = find(q);
        if(pp == qq) return;
        if(rank[pp] > rank[qq]){
            id[qq] = pp;
            rank[pp] += rank[qq];
        }
        else{
            id[pp] = qq;
            rank[qq] += rank[pp];
        }
        count--;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值