思想综述
并查集(Union-Find)算法的主要操作包括两种:
- 合并(Union):将两个不相交的集合合并成一个集合。
- 查询(Find):查询两个元素是否属于同一个集合。
并查集算法的核心思想是使用树(通常是森林)来表示这些不相交的集合,其中每个集合被表示为一棵树,树的根节点代表这个集合的标识(或称为代表元素)。通常,我们会选择树的根节点作为该集合的代表元素,因为这样可以很方便地通过比较两个元素的根节点来判断它们是否属于同一个集合。
自定义结构体
typedef struct node{
int fa, rk;
}Node;
算法实现要点
-
初始化:开始时,每个元素各自构成一个单元素的集合,即每棵树的根节点就是它唯一的节点。
Node ifo[sz];//ifo数组记录每个结点的直接父亲 void initialize(int num)//num为已知的节点总数,即要初始化的ifo结点个数 { for(int i=1; i<=num; i++) { ifo[i].fa = i;//i结点的初始直接父亲设为自己 ifo[i].rk = 0;//以i结点为根的树的初始高度为0 } }
-
查找祖先(Find_fa):为了找到某个元素的根节点(即它所在集合的代表元素),我们可以从该元素开始,沿着父节点的链接一直向上遍历,直到到达根节点。为了提高效率,常用的技巧是路径压缩(Path Compression),即在查找过程中,直接将每个节点链接到根节点上,这样下次查找时就可以直接到达根节点,从而减少查找时间。
int find_fa(int a)#利用递归思想一路查找上去,直到找到根节点 { if(ifo[a].fa == a) return ifo[a].fa;//根节点特点:直接父亲是自己 return find_fa(ifo[a].fa);//返回根节点序号 }
-
合并(Union):合并两个集合时,首先需要找到这两个集合各自的根节点。然后,将其中一个根节点的父节点设置为另一个根节点,从而将两个集合合并为一个集合。为了保持树的平衡,有时会选择较小(或较浅)的树作为另一棵树的子树,这可以通过比较两个根节点的秩(rank,即树的高度)来实现。不过,在许多应用中,直接合并而不考虑秩也是可行的,因为并查集的主要目的是快速判断元素是否属于同一集合,而不是维护树的具体形态。
void Union(int a, int b) { int fa_a = find_fa(a); ifo[a].fa = fa_a;//"压缩路径",直接将每个节点链接到根节点上 int fa_b = find_fa(b); ifo[b].fa = fa_b;//"压缩路径",直接将每个节点链接到根节点上 if(ifo[fa_a].rk < ifo[fa_b].rk) { ifo[fa_a].fa = fa_b; } else{ ifo[fa_b].fa = fa_a; if(ifo[fa_a].rk == ifo[fa_b].rk) ifo[fa_a].rk++; } }
实战例题
【PTA】7-4 朋友圈(C++ * 并查集思想)代码实现 & 一点反思_朋友圈pta-CSDN博客
~ 希望对你有帮助 ~
标签:ifo,浅谈,int,查集,fa,集合,例题,节点,rk From: https://blog.csdn.net/H13420972436/article/details/140123064