c++初级并查集知识点总结
并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题。
有一个联合- 查找算法定义了两个用于此数据结构的操作:
- Find :确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
- Union:将两个子集合并成同一个集合。
并查集主要运用在合并元素以及查询两个元素是否在同一集合的问题,在信息学竞赛中广泛涉及
初始化:
一开始,每一个元素都是一个集合,打个比方,每个人所在的 " 家族 " 只有他一个人。我们还需要一个 f 数组,里面存的是他的 “父亲” 的编号,初始值为 f[1]=1,f[2]=2……f[n]=n,如图
2、find函数:find(a)是用来查找a的“祖先”的,例如,我们要查找 a 的祖先,就要去找 a 的父亲的父亲……,直到有个人 b ,他的父亲就是他自己,那么 b 就是 a 的祖先代码如下:int find (int x){ if(f[x] == x) return x;//如果x的父亲就是他自己,则x为a的祖先 else return find (f[x]);//否则a的祖先 就是a的父亲的祖先}int x=find(a);find函数:find(a)是用来查找a的“祖先”的,例如,我们要查找 a 的祖先,就要去找 a 的父亲的父亲……,直到有个人 b ,他的父亲就是他自己,那么 b 就是 a 的祖先代码如下:int find (int x){ if(f[x] == x) return x;//如果x的父亲就是他自己,则x为a的祖先 else return find (f[x]);//否则a的祖先 就是a的父亲的祖先}int x=find(a);
union函数:
union(a,b) 就是合并 a,b 这两个人所在的家族,只需要把 a的祖先的父亲 指向 b的祖先
如何合并?我们设 u=find(a),v=find(b) , 只要将 u,v 其中一个人的父亲编号指向另外一个人就行了,例如 f[u]=v
代码如下:
void Union (int a,int b)//因为union是c++的保留字,所以只好大写u { int u= find(a), v= find(b);//寻找a,b的祖先 f[u]=v;//合并家族 } Union (a,b);
在合并的时候还有一个注意点:为什么不能直接把 a 的父亲指向 b ?因为这样并不能合并完全,a 的父亲, a 的父亲的父亲……,都不能合并到 b 的家族里(想一想,为什么?),如图
5、查询两个元素是否在同一集合里:查询 a,b 是否在同一集合里,就是看他们的祖先是否相等,若相等则在同一集合里,否则就不在代码如下:if( find(a) == find(b) ) cout<<"Y\n"; //如果祖先相等就输出“Y”else cout<<"N\n"; //否则输出“N”查询两个元素是否在同一集合里:查询 a,b 是否在同一集合里,就是看他们的祖先是否相等,若相等则在同一集合里,否则就不在代码如下:if( find(a) == find(b) ) cout<<"Y\n"; //如果祖先相等就输出“Y”else cout<<"N\n"; //否则输出“N”
例题:
至此,你应该对并查集有了初步的了解,是时候上例题了
题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入输出格式
输入格式:
第一行包含两个整数N、M,表示共有N个元素和M个操作。
接下来M行,每行包含三个整数Zi、Xi、Yi
当Zi=1时,将Xi与Yi所在的集合合并
当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N
输出格式:
如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N
其实,这道题目就是把上面几个步骤综合在一起,代码如下
并查集的路径压缩
路径压缩,顾名思义,就是将本来要很多步完成的事情压缩成一步
因为我们每次 find(a) 都要消耗 O (a 的层数 ) 的时间,如果数据构造成一条链,则每次 find 都需要 O(n) 的时间,这是我们不希望看到的
所以,我们可以把 f 数组的性质改变一下 f[a] 指向的编号变为 a 的祖先
代码该怎么写呢?我们只需要在 find 函数里把
return find (f[x]);
变成
return f[x]=find(f[x]);
就可以了
这样每一次 find 都会使路径上的每个 f[x] 指向 x 的祖先,每一次 find 也就只需要 1 步就行了(除非被合并过,那也只需要 2 步),这就是路径压缩的实质
您可能感兴趣的文章
- 04-02c语言没有round函数 round c语言
- 01-10如何判断一个数是否为2的幂次方?若是,并判断出来是多少次方
- 01-10深入理解C++中常见的关键字含义
- 01-10使用C++实现全排列算法的方法详解
- 01-10如何判断一个数是否为4的幂次方?若是,并判断出来是多少次方
- 01-10c++中inline的用法分析
- 01-10用C++实现DBSCAN聚类算法
- 01-10全排列算法的非递归实现与递归实现的方法(C++)
- 01-10C++大数模板(推荐)
- 01-10浅谈C/C++中的static与extern关键字的使用详解
阅读排行
本栏相关
- 04-02c语言函数调用后清空内存 c语言调用
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言的正则匹配函数 c语言正则表达
- 04-02c语言用函数写分段 用c语言表示分段
- 04-02c语言中对数函数的表达式 c语言中对
- 04-02c语言编写函数冒泡排序 c语言冒泡排
- 04-02c语言没有round函数 round c语言
- 04-02c语言分段函数怎么求 用c语言求分段
- 04-02C语言中怎么打出三角函数 c语言中怎
- 04-02c语言调用函数求fibo C语言调用函数求
随机阅读
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10delphi制作wav文件的方法
- 01-10SublimeText编译C开发环境设置
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 01-11ajax实现页面的局部加载
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-10C#中split用法实例总结
- 04-02jquery与jsp,用jquery