初识并查集

Posted zymmyz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识并查集相关的知识,希望对你有一定的参考价值。

  并查集,首先它是一个集合,集合中的元素是互不相交的集合。如:{{1, 2, 3}, {4}, {5}}

  并查集,集如其名。对并查集的有效操作只有两种:

一.合并两个子集

二.查询并查集的某两个元素是否属于同一个子集

 

  传说,江湖中有一个神奇的小茗世家,江湖各处都有小茗世家的间谍,小茗世家无处不在,势力庞大,是江湖人最敬畏的对象。直到有一天,小茗甲与小茗乙产生了一些矛盾,但他们互不认识,他们调动自己手上小茗世家的力量,想要杀死对方,最后落得同归于尽的下场。他们两个都是小茗世家里位高权重的人物,这一战,直接损失了小茗世家四成的力量!!!小茗家主悲痛之余,决心要改变这种情况,不再使自相残杀的惨剧发生。他想出了一个好办法,既能使尽可能少的人知道小茗世家的间谍,又让他们不会自相残杀。每一个小茗间谍,都会有上级,上级又有上级,直到家主。如果,小茗丙和小茗丁想知道对方是不是自己人,只需要汇报自己的上级,一直汇报到家主。他们发现自己有同样的家主,就知道原来我们是自己人,就不会自相残杀了。

 

  并查集就是这样的道理,每个子集都会有自己的代表元素,称为根元素。每一个元素又有自己的父亲元素(根元素的父亲元素是自己),这样想知道两个元素是否在同一子集,只需要知道他们的根元素是否相同。而合并两个子集,只需要一个根元素退位让贤,另一个根元素统领两个子集就行了。

  

  对于并查集的两个有效操作,最重要的就是找到该元素的根元素。那么该怎么办呢?我们可以开一个father数组,存储每个元素的父亲元素。然后递归找到父亲的父亲……直到找到根元素为止。那么怎么判断一个元素找到了根元素呢?一个元素的父亲元素是自己,它就是根元素啦

  

 1 #define maxsize 1000010
 2 
 3 int father[maxsize];
 4 
 5 int getroot(int x) {
 6     if (father[x] == x) {
 7         return x;
 8     }
 9     else {
10         int father = father[x];
11         return getroot(father);
12     }
13 }

 

   但这样时间复杂度会不会很高呢?没关系,我们有更高级的路径压缩大法:

 1 #define maxsize 1000010
 2 
 3 int father[maxsize];
 4 
 5 int getroot(int x) {
 6     if (father[x] == x) {
 7         return x;
 8     }
 9     else {
10         int root = getroot(father[x]);
11         father[x] = root;
12         return root;
13     }
14 }

  对于我们找过的元素,我们直接使他的父亲节点为根元素,这样就大大的减少了寻找根元素的时间了

 

  接下来就是两个基本操作的实现了:

  合并两个子集:

 1 #define maxsize 1000010
 2 
 3 int father[maxsize];
 4 
 5 void merge(int x, int y) {
 6     int xroot = getroot(x);
 7     int yroot = getroot(y);
 8 
 9     father[yroot] = xroot;
10 }

 

  查询并查集中某两个元素是否属于同一子集:

 1 #define maxsize 1000010
 2 
 3 int father[maxsize];
 4 
 5 bool isSameRoot(int x, int y) {
 6     int xroot = getroot(x);
 7     int yroot = getroot(y);
 8 
 9     if (xroot == yroot) {
10         return true;
11     }
12     else {
13         return false;
14     }
15 }

以上是关于初识并查集的主要内容,如果未能解决你的问题,请参考以下文章

树的应用——并查集及实现代码

想要学会并查集吗?看我四十行代码实现它

树--12---并查集

笔记并查集---无向图处理代码模板及类型题

并查集

力扣 每日一题 886. 可能的二分法难度:中等,rating: 1794(并查集 / 拆点优化的扩展域并查集)