并查集查找的速度非常快,同时也能反映数据之间的关系。下面着重介绍并查集的生成方法
一开始先初始化,使得每一个节点的父亲都是他本身。然后要如何体现他们之间的关系呢?
这时就要写一个函数,这个函数接受两个参数a,b,然后找到a与b的父亲,令a的父亲=b的父亲(反之也可),这样a,b就在一起了,都归b或者a的父亲管。
但是,这样写会造成一个问题,树很容易退化成链表,使得效率大大降低,树层数太大,例如:
我要找到a的父亲,如果当前父亲的父亲不等于他自身,那么路径最差可能是这样的:
a->b的父亲->c的父亲......并不满意
压缩路径,防止退化:
我们要控制树每一层的节点数,压缩路径,使得每一层的节点数都大致相等,也就是让大树与小树合并一下,
如果a的高度小于b的高度,那么我们就让a的父亲等于b的父亲(这里与先前的有差别,先前的不管树的高度,a、b的父亲成为新树的父亲都可以),否则我们就让b的父亲等于a的父亲
#include <iostream>
#include<cstdio>
using namespace std;
//int fa[10005];
struct father
{
int data;
int weight;
int h;
} fa[10005];
int init(int n)
{
for(int i=1; i<=n; i++)
{
fa[i].data=i;//一开始根是自身
fa[i].h=0;
fa[i].weight=1;
}
}
int find_set(int i)
{
return fa[i].data==i?i:fa[i].data=find_set(fa[i].data);//返回根,将查询路径的根节点赋值为最终的根节点
}
int merge_set(int a,int b)
{
int x=find_set(a);
int y=find_set(b);
if(x!=y)
{
if(fa[x].h<fa[y].h)
{
fa[x].data=fa[y].data;//代表把a的根指向b的根
fa[y].weight+=fa[x].weight;//加权值
}
else
{
fa[y].data=fa[x].data;
fa[x].weight+=fa[y].weight;
if(fa[x].h==fa[y].h)
fa[y].h++;
}
}
return 1;
}
int main()
{
freopen("in.txt","r",stdin);
int n=0;
cin>>n;
init(n);
merge_set(2,5);
merge_set(2,4);
for(int i=1;i<=n;i++)
{
cout<<fa[i].data<<" "<<fa[i].weight<<"\n";
}
}