并查集总结
今天总结一下并查集,这个完了之后,寒假学的数据结构基础的模板类的题目差不多就完了,对于模板题,敲上10遍、20遍、30遍,那么模板就不是模板,就成为了你自己的东西,就好像 A+B 一辈子也忘不了,以后每天敲一遍模板题,加深对模板的理解。
并查集,一般使用的是 数组实现、树实现,其中数组实现时间复杂度较高,树实现也就是分离集合森林 查找、合并的时间复杂度不会
超过 O(log2n)
一、树实现
今天总结一下并查集,这个完了之后,寒假学的数据结构基础的模板类的题目差不多就完了,对于模板题,敲上10遍、20遍、30遍,那么模板就不是模板,就成为了你自己的东西,就好像 A+B 一辈子也忘不了,以后每天敲一遍模板题,加深对模板的理解。
并查集,一般使用的是 数组实现、树实现,其中数组实现时间复杂度较高,树实现也就是分离集合森林 查找、合并的时间复杂度不会
超过 O(log2n)
n个人,m对有亲戚关系的
10 7
1 2
2 3
2 4
3 4
5 6
6 7
8 9
初始化:{1} {2} {3} {4} {5} {6} {7} {8} {9} {10}
初步合并 {1,2} {2,3} {2,4} {3,4} {5,6} {6,7} {8,9} {10}
最终合并 {1,2,3,4} {5,6,7} {8,9} {10}
分离集合森林如下:
一、树实现
并查集中,每一个集合代表一个分离集合树,多个集合形成一个森林,树根当做集合的代表,每一个节点都有一个父指针来表示附属关系,根节点指向自身,在一个树高度很低的树种查找一个节点所用的时间很少。所以 并查集的分离集合树的 开辟一个秩的int 数据来保证构造的分离集合树的高度较低,在合并的时候,让较小的秩的根指向较大秩的根,若俩个秩相等,任意一个指向另一个,并且它的秩+1;
POJ 2524
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
const int N= 50001;
using namespace std;
struct node{
int data; // 节点数据域
int zhi; //秩 存放子树高度
int parent;//父节点
}t[N];
int n,m;
int Find(int r)//查
{
while(t[r].parent!=r)//判断双亲是不是自己
{
r = t[r].parent; //循环查找X,
}
/*
if(t[r].parent==r) //递归实现
return r;
else
return (Find(t[r].parent));
*/
int i=r,j;//压缩路径
while (t[i].parent!=r)//i的父亲不是r,进行压缩
{
j=t[i].parent;//记录i的父亲
t[i].parent=r;//改变i的父亲
i=j;//判断i的父亲
}
return r;
}
void Merge(int x,int y)//并:合并x y的子树
{
x = Find(x); //找x所在子树的编号
y = Find(y);
if(t[x].zhi>t[y].zhi) //较小秩 指向 较大秩
{
t[y].parent = x; //y链接到x上,x为父节点
}
else
{
t[x].parent = y;
if(t[x].zhi == t[y].zhi) //x连接y,y做为父节点
t[y].zhi++; //y的子树高度+1
}
}
void init()
{
for(int i = 1;i<=n;i++)
{
t[i].data = i;
t[i].zhi = 0;//初始化 树高度为0
t[i].parent = i;//父节点是自己
}
}
int main()
{
int x,y,l=0;
while(scanf("%d%d",&n,&m))
{
if(n==0 && m==0)
break;
l++;
init();
for(int i = 0;i<m;i++)
{
scanf("%d%d",&x,&y);
Merge(x,y);
}
int sum = 0;
for(int i = 1;i<=n;i++)
{
if(t[i].parent!=i)
sum++;
}
printf("Case %d: %d\n",l,n-sum);
}
return 0;
}
数组实现
#include <stdio.h>
int bin[100010];
int findx(int x)
{
int r=x;
while(bin[r] !=r)
r=bin[r];
return r;
}
void merge(int x,int y)
{
int fx,fy;
fx = findx(x);
fy = findx(y);
if(fx != fy)
bin[fx]=fy;
}
int main()
{
int n,m,i,x,y,count;
int t=1;
while(~scanf("%d%d",&n,&m))
{
if(n==0 && m == 0)
break;
for(i=1;i<=n;i++)
{
bin[i] = i;
}
for(i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
merge(x,y);
}
for(count = 0, i=1;i<=n;i++)
if(bin[i] == i)
count ++;
printf("Case %d: %d\n",t++,count);
}
return 0;
}