您的位置:首页 > 其它

并查集模板

2013-07-20 23:11 169 查看
普通并查集:

#define MAX_SIZE 100005
int pa[MAX_SIZE];        //存储有向图的边

void init()     //初始化	该函数可以根据具体情况保存和初始化需要的内容
{
for(int i = 0; i < MAX_SIZE; i++)
{
pa[i] = i;
}
}

int findset(int a)	//不带路劲压缩
{
while(pa[a] != a)
{
a = pa[a];
}
return a;
}

void union_nodes(int a, int b)      //集合合并
{
int a1 = findset(a);
int b1 = findset(b);
if(a1 != b1)		//这个判定条件可选,主要是为了防止findset路径压缩的时候出现死循环
{
pa[a1] = b1;		//如果存的是有向图,并且做题时集合中元素的顺序很重要,不能忽略,那么这里应该用"pa[a] = b;"
}
}


带路径压缩的的findset函数:

1.while版本

int findset(int v)      //找元素所在集合的代表元(因为用了路径压缩,路径压缩的主要目的是为了尽快的确定元素所在的集合)
{
int t1,t2=v;
while(v!=pa[v])
v=pa[v];
while(t2!=pa[t2])        //这里优化的思路还是路径压缩(进一步的在查找函数执行的过程中压缩路径),很神奇!
{
t1=pa[t2];
pa[t2]=v;
t2=t1;
}
return v;
}


2.递归版本

int findset(int x)
{
if(pa[x] != x)
{
int root = findset(pa[x]);
return pa[x] = root;
}
else
{
return x;
}
}


个人经验表明在递归版本不栈溢出的情况下,递归版本和循环版本的效率并没有太大差别,并且对于带路径压缩的并查集,基本上不会发生“递归栈溢出”。

另外,union_nodes函数还可以可以采用启发式合并,思路就是把深度较小的那棵子树并到深度较大的那棵子树上,不过一般情况下路径压缩就够用了。

听人说并查集还可以“离散化”,个人从字面上理解应该是指用map、hash来保存每个节点,从而当节点分布比较稀疏的时候,可以比普通并查集更快的完成初始化等工作(待商榷)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: