并查集讲解

博客介绍了并查集这一数据结构,它可快速查询集合元素间是否有关系,判断标准是有无相同根节点。还阐述了普通查询思路,即追溯祖父节点判断关系,同时给出了O(1)优化方法,通过更新父节点减少重复劳动,最后整理出该数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是并查集

img

并查集是一种数据结构,用来快速查询集合元素之间是否有关系,是否有关系判断标准是是否有相同的根节点

举一个恰当的例子,要判断图谱中的两个元素是否有关系,如果使用常规的查询方法,时间复杂度比较大,使用并查集就是用来优化这种情况,使得判断两个元素是否有关联可以达到O(1)

普通查询思路

按照上图,要判断11和4是否有关系,我们可以一直向上追溯父亲节点,11的上层是9,9的上层节点是0,那么11的祖父节点就是0。同理,追溯4的祖父节点是0,那么这两个节点的祖父节点都是0,则两个节点有关系

知道了思路,抽象出代码就很简单了,现在要解决的有两个问题,使用非递归,从下往上进行追溯,什么时候是截止条件呢,可以让0号节点的父节点指向自己。第二个问题就是如何存储这样一个结构,由于每个节点只需要用到父节点,可以使用map来进行存储,代码如下:

        //找a的祖父节点
		int father = map.get(a);
        while (father != map.get(father)) {
            father = map.get(father);
        }
O(1)优化

按照上面的思路一级一级的追溯,很明显时间复杂度是O(n),如何进行优化呢

举个例子,当查询过一遍4的祖父节点是0的时候,我们就可以直接更新4的父节点是0,后续再使用到4的时候,就不会做重新劳动了,我们可以继续思考,既然用到4了,我们可以直接将4开始往上所有的路径节点都直接更新

所以,整个思路分为两步,第一步还是先找到顶级根节点,第二步从当前节点开始往上,依次更新父节点

		//找a的祖父节点
		int father = map.get(a);
        while (father != map.get(father)) {
            father = map.get(father);
        }

		//从当前节点往上更新父节点
		int temp = -1;
		int fa = map.get(a);
		while(fa != map.get(fa)) {
            //temp保存原父节点,防止更新后丢失
            temp = map.get(fa);
            map.put(fa,father);
            fa = temp;
        }
数据结构

根据上面的思路,就可以整理出来该数据结构

class UnionFind {
    HashMap<Integer,Integer> map;

    public UnionFind() {
        map = new HashMap<>();
    }

    //初始化所有节点,每个节点的父节点都指向自己
    public void find0() {
        //... 这里根据情况来写,遍历每个父节点指向自己
    }

    public int find(int num) {
        int father = map.get(num);
        while (father != map.get(father)) {
            father = map.get(father);
        }

        //从当前节点往上更新父节点
        int temp = -1;
        int fa = map.get(num);
        while(fa != map.get(fa)) {
            //temp保存原父节点,防止更新后丢失
            temp = map.get(fa);
            map.put(fa,father);
            fa = temp;
        }

        return father;
    }
    
    //合并
    public void union(int a,int b) {
        int fa_a = find(a);
        int fa_b = find(b);
        if(fa_a != fa_b) {
            map.put(fa_a,fa_b);
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值