并查集 ——(快速判断两个元素是否在同一个集合中)

五、并查集

0、并查集概念

并查集(Union-Find)是一种用于维护元素分组信息的数据结构。它支持以下两种基本操作:

  1. 合并(Union):将两个不同的集合合并为一个集合。
  2. 查找(Find):确定某个元素属于哪个集合。

并查集通常用于解决涉及集合合并和查询的问题,例如:

  • 连通性问题:判断两个元素是否在同一个连通分量中。
  • 图的连通性问题:判断一个无向图是否连通。
  • 基于并查集的最小生成树算法,如Kruskal算法。

并查集的实现主要有两种:
1、基于数组的并查集:使用一个数组来表示集合,数组中的每个元素代表该元素所属的集合的代表元素。
2、基于树的并查集:使用树结构来表示集合,每个集合用一棵树表示,树的根节点就是该集合的代表元素。

image.png

1、模拟实现并查集

import java.util.Arrays;

public class UnionFindSet {
    public int[] elem;

    public UnionFindSet(int n) {
        this.elem = new int[n];
        Arrays.fill(elem,-1);
    }

    /**
     * 查找数据x 的根节点
     * @param x
     * @return 下标
     */
    public int findRoot(int x) {
        if(x < 0) {
            throw new IndexOutOfBoundsException("下标不合法,是负数");
        }
        while (elem[x] >= 0 ) {
            x = elem[x];//1  0
        }
        return x;
    }

    /**
     * 查询x1 和 x2 是不是同一个集合
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1,int x2) {
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) {
            return true;
        }
        return false;
    }

    /**
     * 这是合并操作
     * @param x1
     * @param x2
     */
    public void union(int x1,int x2) {
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) {
            return;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    public int getCount() {
        int count = 0;
        for (int x : elem) {
            if(x <  0) {
                count++;
            }
        }
        return count;
    }

    public void print() {
        for (int x : elem) {
            System.out.print(x+" ");
        }
        System.out.println();
    }

    //省份的数量
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UnionFindSet ufs = new UnionFindSet(n);
        for(int i = 0;i < isConnected.length;i++) {
            for(int j = 0;j < isConnected[i].length;j++) {
                if(isConnected[i][j] == 1) {
                    ufs.union(i,j);
                }
            }
        }
        return ufs.getCount();
    }

    //等式的满足性
    public boolean equationsPossible(String[] equations) {
        UnionFindSet ufs = new UnionFindSet(26);
        for(int i = 0; i < equations.length;i++) {
            if(equations[i].charAt(1) == '=') {
                ufs.union(equations[i].charAt(0)-'a',equations[i].charAt(3)-'a');
            }
        }
        for(int i = 0; i < equations.length;i++) {
            if(equations[i].charAt(1) == '!') {
                int index1 = ufs.findRoot(equations[i].charAt(0)-'a');
                int index2 = ufs.findRoot(equations[i].charAt(3)-'a');
                if(index1 == index2) {
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        String[] str = {"a==b","b!=a"};
        //equationsPossible(str);
    }

    //亲戚题
    public static void main2(String[] args) {
        int n = 10;
        int m = 3;
        int p = 2;

        UnionFindSet unionFindSet = new UnionFindSet(n);

        System.out.println("合并:0和6:");
        unionFindSet.union(0,6);
        unionFindSet.union(0,1);
        System.out.println("合并:3和7:");
        unionFindSet.union(3,7);
        System.out.println("合并:4和8:");
        unionFindSet.union(4,8);

        System.out.println("以下是不是亲戚:");
        boolean flg = unionFindSet.isSameUnionFindSet(1,8);
        if(flg) {
            System.out.println("是亲戚!");
        }else {
            System.out.println("不是亲戚!");
        }
        System.out.println("当亲的亲戚关系 "+unionFindSet.getCount()+" 对!");
    }

    public static void main1(String[] args) {
        UnionFindSet unionFindSet = new UnionFindSet(10);
        System.out.println("合并:0和6:");
        unionFindSet.union(0,6);
        System.out.println("合并:0和7:");
        unionFindSet.union(0,7);
        System.out.println("合并:0和8:");
        unionFindSet.union(0,8);

        System.out.println("合并:1和4:");
        unionFindSet.union(1,4);
        System.out.println("合并:1和9:");
        unionFindSet.union(1,9);
        System.out.println("合并:2和3:");
        unionFindSet.union(2,3);

        System.out.println("合并:2和5:");
        unionFindSet.union(2,5);

        unionFindSet.print();

        System.out.println("合并:8和1:");
        unionFindSet.union(8,1);

        unionFindSet.print();

        System.out.println("查找是不是同一个集合");
        System.out.println(unionFindSet.isSameUnionFindSet(6, 9));
        System.out.println(unionFindSet.isSameUnionFindSet(8, 2));

    }
}

2、并查集主要功能

image.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值