一、什么叫并查集
并查集支持查找一个元素所属的集合以及两个元素各自所属的集合的合并等运算。当给出两个元素的一个无序对(a,b)时,需要快速“合并”a和b分别所在分别所在的集合,这期间需要反复“查找”某元素所在的集合。“并”、“查”、“集”三个字由此而来。
例如,如果已经得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系就十分复杂。在这种情况下,就需要应用并查集。
二、并查集的算法实现
1.并查集树的初始化
2.查找一个元素所属的集合
3.两个元素各自所属的集合的合并
- #include<stdio.h>
- typedef struct node//并查树的节点类型
- {
- int data;//节点对应的编号
- int rank;//树的高度
- int parent;//节点对应双亲的下标
- }UFSTree;
- void MAKE_SET(UFSTree t[], int N)//初始化并查集树
- {
- int i;
- for (i=0;i<N;i++)
- {
- t[i].data=i;
- t[i].rank=0;
- t[i].parent=i;
- }
- }
- int FIND_SET(UFSTree t[], int x)//找出x的树根(集合的代表)
- {
- if(x!=t[x].parent)
- return(FIND_SET(t, t[x].parent));
- else
- return(x);
- }
- void UNION(UFSTree t[], int x, int y)//将x和y所在的子树合并
- {
- x=FIND_SET(t, x);
- y=FIND_SET(t, y);
- if(t[x].rank>t[y].rank)//把小树合并到大树下
- t[y].parent=x;
- else
- {
- t[x].parent=y;
- if(t[x].rank==t[y].rank)
- t[y].rank++;
- }
- }
- int main()
- {
- int N, M, i, num;
- int a, b;
- int person_1[100], person_2[100];
- UFSTree T[100];
- printf("请输入人数:");
- scanf("%d", &N);
- printf("请输入已知的关系的组数:");
- scanf("%d",&M);
- MAKE_SET(T, N);
- printf("\n");
- for(i=0;i<M;i++)
- {
- printf("请输入第%d组的信息:", i+1);
- scanf("%d %d", &a, &b);
- UNION(T, a, b);
- }
- printf("\n请输入需要查询的组数:");
- scanf("%d", &num);
- printf("\n");
- for(i=0;i<num;i++)
- {
- printf("请输入需要查询的第%d组的两个人:", i+1);
- scanf("%d %d", &person_1[i], &person_2[i]);
- }
- printf("\n");
- for(i=0;i<num;i++)
- {
- printf("%3d%3d", person_1[i], person_2[i]);
- if(FIND_SET(T, person_1[i])==FIND_SET(T, person_2[i]))
- printf(" Yes\n");
- else
- printf(" No\n");
- }
- }
- /*输入样例
- 人数:10
- 已知的关系组数:7
- 2 4
- 5 7
- 1 3
- 8 9
- 1 2
- 5 6
- 2 3
- Q=3
- 3 4
- 7 10
- 8 9
- */