一文看明白并查集

简介: 一文看明白并查集

什么是并查集


并查集本质就是集合。


  • 并查集可以进行集合合并的操作(并)
  • 并查集可以查找元素在哪个集合中(查)
  • 并查集维护的是一堆集合(集)

对于并查集我们需要知道两个信息

  • 元素的值
  • 集合的标号


用什么样的数据结构表示并查集?


我们能不能让一个数组存储每个节点的父节点,连成一棵树呢?


初始时每个节点都是一个单独的集合,父节点指向自己,

如果要合并两个集合,那么将a的父节点设为b,将a插入到b节点下充当子节点

那么如何判断是否是同一集合呢? 就看祖宗节点是否相同,如果相同则代表是同一集合


初始化:


1. 
int []p=new int[N];   //存储每个节点的父节点
2. for (int i = 1; i <=n; i++)  p[i]=i;


返回x的祖宗节点:


    public static int find(int x){
        if(p[x]!=x)  
      p[x]=find(p[x]); //将x的父亲置为x父亲的祖先节点,实现路径的压缩
        return p[x];
    }


find的功能是用于查找祖先节点,那么路径压缩又是怎么完成的


合并为同一集合:


p[find(a)] = find(b);


查找是否同一集合


find(a) == find(b)


如果想知道每一个集合的数量呢?


我们引入一个size集合,存储每个节点自己的数量+子孙节点的数量,

那么祖宗节点的size就是整个集合的数量,即size[find(a)]

初始化:


  for (int i = 1; i <=n; i++) {
            p[i]=i;
            size[i]=1;
   }


合并为同一集合:


1.  p[find(a)] = find(b);
2.  size[find(b)]+=size[find(a)]


给一个例题 连通块中点的数量


给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。


现在要进行 m个操作,操作共有三种:


C a b,在点 aa 和点 bb 之间连一条边,aa 和 bb 可能相等;


Q1 a b,询问点 aa 和点 bb 是否在同一个连通块中,aa 和 bb 可能相等;


Q2 a,询问点 aa 所在连通块中点的数量;


输入格式


输入样例:5 5C 1 2Q1 1 2Q2 1C 2 5Q2 5
输出样例:Yes23


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
    static int N=100010;
    static int []p=new int[N];   //存储每个节点的父节点
    static int []size=new int[N];  //查询根节点,得到整个集合数量
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String []s=br.readLine().split(" ");
        int n=Integer.parseInt(s[0]),m=Integer.parseInt(s[1]);
        for (int i = 1; i <=n; i++) {
            p[i]=i;
            size[i]=1;
        }
        while (m-->0){
            String []fir=br.readLine().split(" ");
            if("C".equals(fir[0])){  //集合合并
                int pa=find(Integer.parseInt(fir[1]));
                int pb=find(Integer.parseInt(fir[2]));
                if(pa!=pb){
                    p[pa]=pb;
                    size[pb]+=size[pa];
                }
            }else if("Q1".equals(fir[0])){
                int pa=find(Integer.parseInt(fir[1]));
                int pb=find(Integer.parseInt(fir[2]));
              if(pa==pb){
                  System.out.println("Yes");
              }else System.out.println("No");
            }else {
                int pa=find(Integer.parseInt(fir[1]));
                System.out.println(size[pa]);
            }
        }
    }
    //返回每个节点的父节点
    public static int find(int x){
        if(p[x]!=x)  p[x]=find(p[x]);
        return p[x];
    }
}
相关文章
|
1月前
|
消息中间件 存储 算法
一文搞懂二分查找算法!
一文搞懂二分查找算法!
|
6月前
|
算法 Java
数据结构奇妙旅程之二叉树题型解法总结
数据结构奇妙旅程之二叉树题型解法总结
|
C语言
【leetcode】学了栈和队列却觉得无用武之地?试试这几道题目吧!
【leetcode】学了栈和队列却觉得无用武之地?试试这几道题目吧!
89 0
|
C语言
排序会了递归,不学非递归太可惜了
排序会了递归,不学非递归太可惜了
87 0
排序会了递归,不学非递归太可惜了
|
算法
这样给面试官解释约瑟夫环问题的几种巧妙解法,面试官满意的笑了
约瑟夫环问题是算法中相当经典的一个问题,其问题理解是相当容易的,并且问题描述有非常多的版本,并且约瑟夫环问题还有很多变形,这篇约瑟夫问题的讲解,一定可以带你理解通通!
146 0
这样给面试官解释约瑟夫环问题的几种巧妙解法,面试官满意的笑了
|
人工智能 算法 大数据
终于有人把面试必考的动态规划、链表、二叉树、字符串全部撸完了
对于计算机专业的毕业生而言,算法岗基本上就是**「高薪」**的代名词。 然而,由于这几年AI方向异常火爆,算法岗似乎也已经承载不下了,计算机视觉就是一个很好的例子,某些公司的录用比例已经达到了**32:1**。 知乎上的问题也从**「是否值得进入」**到**「供大于求」**再到**「诸神黄昏」**、**「灰飞烟灭」**、**「车毁人亡」**,一年比一年夸张。
108 0
终于有人把面试必考的动态规划、链表、二叉树、字符串全部撸完了
|
算法
我明白了,leetcode91题
91题**解码方法**的难度属于中等,但其涉及到的知识并不少呢,斐波那契、备忘录剪枝、动态规划等等,除了题解之外,我也会深入浅出的讲解这些知识点,文章末尾我还会使用 正则 + 斐波那契的写法来解题,我们一起来看看。
141 0
我明白了,leetcode91题
蓝桥杯——修改数组(思维+并查集)
蓝桥杯——修改数组(思维+并查集)
120 0