并查集及其应用

并查集


  并查集(Union-Find)是解决动态连通性问题的一类非常高效的数据结构。
  这里以整数 0~9 表示图中的10个点,然后给出两两连通的数据如下:[(4, 3), (3, 8), (6, 5), (9, 4), (2, 1), (8, 9), (5, 0), (7, 2), (6, 1), (6, 7)]。如何让计算机读取这些数据来构建一种数据结构(合并连通点),然后在这种数据结构上高效的做出对某个点对是否连通的判断(查询连通性)。这也就是并查集名字的由来了。为了实现上面所描述的功能,一个简单的思路就是分组。也就是说,我们可以把相互连通的点看成一个组,如果现在查询的点对分别在不同的组中,则这个点对不连通,否则连通。下面我们先来简单分析一下这种操作的具体过程,分“并”和“查”两个方面来分析。为了方便描述,我这里先举一个例子:比如上图的10个点,现在就令每个点的值为其初始组别,我们可以得到下面这个表:

element0123456789
parent0123456789

现在,“并”的操作可以这样来描述:观察第一个点对(4,3),于是先找到点4和3,发现所在组别不一样,再将点4和3的组别都变成3(当然都变成4也行,这个随意设计),然后就产生了如下的表:

element0123456789
parent0123356789

而“查”的操作其实就是“并”操作的第一步:找到点对中两个点所在的组别,看是否相同。也就是说,并查集的两类基本操作中,都涉及了“根据点找组别”的过程,因此我们先给出一个高效的“查”的算法。我把它叫做Quick-Find 算法。
例题
  输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int[] re=new int[2];
        DFS dfs=new DFS(edges.length);
        dfs.union(edges[0][0]-1,edges[0][1]-1);
        for(int i=1;i<edges.length;i++){
            if(dfs.find(edges[i][0]-1)==dfs.find(edges[i][1]-1)){
                re[0]=edges[i][0];
                re[1]=edges[i][1];
            }else{
                dfs.union(edges[i][0]-1,edges[i][1]-1);
            }
        }
        return re;
    }
}
class DFS{
    int[] parent;
    public DFS(int n){
        parent=new int[n];
        for(int i=0;i<n;i++){
            parent[i]=i;
        }
    }
    public int find(int x){
        if(parent[x]!=x){
            parent[x]=find(parent[x]);
        }
        return parent[x];
    }
    public void union(int p,int q){
        parent[find(q)]=find(p);
    }
}

此题使用并查集解决。对于同一棵树的所有节点来说,都拥有共同的祖先节点。因此,判断冗余连接的条件即为,判断新加入的边,两个节点是否有共同的祖先。
(1)如果有共同的祖先,则说明这条边是冗余的边
(2)如果没有共同的祖先,则说明这两条边并未加入树中,因此进行合并操作
循环边的记录,获取最后出现的冗余边,就是答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值