算法-并查集1

什么是并查集:

并查集更像是一些元素的集合,我们把每个集合都用一棵树来表示。

并查集有什么用处:

1.将两个集合合并
2.询问两个元素是否在同一个集合中
优化后(路径压缩)可以在近乎O(1)的复杂度完成这两个操作。

基本原理:

集合是需要编号来告诉我们这些元素是属于哪个集合的,所以我们定义树根的编号就是整个集合的编号,我们也是用树的形式来维护每个集合的。用P[]数组储存父节点:p[x]储存x的父节点。

功能实现:

1.如何判断一个点是不是树根 ?
如果这个元素的父节点就是它本身,就代表这个点是树根。

if(p[x] == x);

代表x是根节点。
2.如何求x的集合编号?

while(p[x] != x){
x = p[x];
}

最后的x值就是它的集合编号。
3.如何合并两个集合?
假设px是x的集合编号,py是y的集合编号

p[x] = y;

进行两集合的合并 。

并查集的优化(路径压缩):

由于原先的查找操作(每一次都从x找x的父节点,再从x的父节点 找到上一层的父节点,直到找到根节点)与树高成正比,所以每一次查找都要一步步查找父节点,直到找到根节点。
所以现在进行优化(路径压缩):让每个子节点的父节点直接指向根节点。

详解实现:

1.初始化:
在这里插入图片描述
2.返回x的根节点+路径压缩(查找):

public static int find(int x){
        if(p[x] != x){
            p[x] = find(p[x]);
        }
        return p[x];
    }

题目

在这里插入图片描述
在这里插入图片描述

题解完整代码(Java)

import java.util.Scanner;

public class Main {
    static int N = 100010;
    static int n;
    static int[] p = new int[N];//存储每个节点的父节点

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        int m = sc.nextInt();
        init();
        while (m-- > 0){
            String s = sc.next();
            int a  =sc.nextInt();
            int b = sc.nextInt();
            if(s.equals("M")){
                p[find(a)] = find(b);//合并操作:让a的祖宗节点的父节点指向b的祖宗节点 ——> a集合并入b集合中
            }else {
                if(find(a) == find(b)){//查询a、b是否在同一集合内:如果a和b的祖宗节点是同一个的话,证明是同一个集合,否则,就不属于同一个集合
                    System.out.println("Yes");
                }else {
                    System.out.println("No");
                }
            }
        }
    }
    //初始化,一开始所有节点的父节点都指向自己
    public static void init(){
        for (int i = 1; i <= n; i++) {
            p[i] = i;
        }
    }
    //返回x的祖宗节点 + 路径压缩
    public static int find(int x){
        if(p[x] != x){//如果x的父节点不是它本身的话,证明x不是祖宗节点,就让x的父节点接着找父节点,直到找到祖宗节点。并且让x的父节点指向祖宗节点,返回祖宗节点。
            p[x] = find(p[x]);
        }
        return p[x];
    }
}

初步并查集学习中,先要了解并查集的功能及其实现,重点理解路径压缩。

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值