并查集
并查集大致就分为三大块,建立集合,查找父节点(即同一集合的结点),集合合并。
并查集是一个浩大的工程,因为它非常的需要空间,所以说他的空间复杂度简直是高的可以,因为如果一组测试数据,是1,2,500000.你就要开一个以最大数为基准的数组,随意数组大小为500000.看到这个数字就惶恐对不,这么大的数据这题是有多难。放心,如果理解了的话,并查集并不很难。无非就是集合之间的操作吗,咱可是有数学功底的人。
讲个栗子
给出以下几个集合:{1,6},{1,4},{1,5},{2,3},{2,9}.包含相同数字的可以合并在一起。
请问一共是几个集合?可以合并不?合并后那?
其实合并后就两个分别是{1,4,5,6}和{2,3,9}。这就是并查集的大致作用了。
全局变量
#define N 101
int set[N];//全局变量,表示集合
int rank[N];
集合建立
void make_set()
{
for(i=1;i<N;i++)
{
set[i]=i;//集合建立,暂且将自己看作单独一个集合
rank[i]=0;//用于辅助按秩合并,下面会做解释
}
return;
}//以上结合建立完毕
集合寻亲
为什么叫“寻亲”(其实不专业-A-),因为业界人士总把某一元素的上一结点或者其他称为“父结点”。所以姑且称为“寻亲”吧。不多BB,写代码。
int find_set(int x)
{
if(x!=set[x])//如果set[x]!=x说明set[x]有父节点,所以就要开始寻找一直向上直至找到祖父节点
set[x]=find_set(set[x]);//寻找set[x]的父节点,此处为递归
return set[x];
}
集合合并
void union_set(int x,int y)//x,y为数组的索引(即数组下标)
{
x=find_set(x);//找到最终节点
y=find_set(y);//同上
if(x == y)//最终节点都指向同一结点,就不需要再合并,因为已经合并,要知道每一个最终节点都代表一个集合,所以他们属于一个集合
return;
else if(rank[x]>rank[y])
set[y]=x;
else
{
set[x]=y
if(rank[x] == rank[y])
rank[y]++;//y的祖父节点增加了一个分支结点。
}
}
写在最后
以上便是并查集的主要部分,如何实现应用还需勤加练习。
泪目°