Yurchiu's Blog

并查集 1

Yurchiu 2019-10-04, 13:53:22 853 隐藏左右两栏 展示左右两栏

本文主要以模板为主。

简介

并查集是一种树型的数据结构,用于处理一些不相交集的合并及查询问题。不相交集,就是交集为空集的一些集合。比如集合 {1,3,5}\{1,3,5\} 和集合 {2,4,6}\{2,4,6\} 就是不相交集。 {2,3,5}\{2,3,5\}{1,3,5}\{ 1,3,5\} 就不是,因为他们的交集不是空集。

形象地来说,有点像“朋友圈”:A 和 B 是朋友,A 和 B 就构成了一个朋友圈,C 和 D 是朋友,C 和 D 也构成了一个朋友圈,那么这时,如果 B 和 C 成为了朋友,A、B、C、D 就构成了一个大的朋友圈。

并查集就是可以描述这种情形的数据结构。

模板

仅使用“路径压缩”优化版。

struct UFDS
{
	ll dad[M],n;
	void init(ll p){ n=p; for(ll i=1;i<=n;i++) dad[i]=i; }
	ll find(ll x)
	{   
   		while(x!=dad[x])
      		x=dad[x]=dad[dad[x]];
 		return x;
	}
	void union_(ll x,ll y)
	{
   		ll d1=find(x),d2=find(y);
   		dad[d1]=d2;
   		return;
	}
	bool check(ll x,ll y)
	{
   		ll d1=find(x),d2=find(y);
   		if(d1==d2)
       		return 1;
   		return 0;
	}
}ufds;

操作

对于并查集,主要有如下操作:

  1. 初始化。
  2. 合并两个集合(并)。
  3. 判断两个元素是否属于同一个集合(查)。

初始化

void start(int n)
{
	for(int i=1;i<=n;i++)
		dad[i]=i;
	return;
}

dad也是父亲的意思。。。

void union_(int x,int y)
{
	int d1=find(x),d2=find(y);
	dad[d1]=d2;
	return;
}

查————代表

递归式

int find(int x)
{
	if(dad[x]==x)
    	return dad[x];
    return find(dad[x]);
}//注意可能会RE

非递归式

int find(int x)
{  
    int root=x;  
    while(root!=dad[root])
        root=dad[root];
    return root;  
}

查————是否在同一集合

bool check(int x,int y)
{
	int d1=find(x),d2=find(y);
	if(d1==d2)
		return 1;
	return 0;
}

优化

路径压缩

递归式

int find(int x)
{
	if(dad[x]==x)
    	return dad[x];
    return dad[x]=find(dad[x]);//<---
}//递归式

非递归式

int find(int x)
{   
    while(x!=dad[x])
        x=dad[x]=dad[dad[x]];
    return x;
}

路径压缩的效率很高(一次操作时间复杂度为 O(α(m,n))O(\alpha(m,n)),可看作很小的常数),可以防止树的形态变为一条链。在一般并查集中应用很广泛,一旦使用路径压缩,原有的父子关系就会被破坏,从而直接建立与祖先的父子关系,可以高效地维护集合之间的从属关系,但是对于每个节点之间的直接关系是不能维护的。

按秩合并

void start(int n)
{
    for(int i=1;i<=n;i++)
        dad[i]=i,rank[i]=0;//树的高度为0
    return;
}
void union_(int x,int y)
{
    int d1=find(x),d2=find(y);
    if(d1==d2) 
        return;
    if(rank[d1]>rank[d2])
        swap(d1,d2);
    dad[d1]=d2;    
    if(rank[d1]==rank[d2])//如果相等,只能增加树高
        rank[d2]++;
    return;//否则树高是不增加的
}

给每个点一个秩(树高),每次合并的时候都用秩小的指向秩大的,可以保证树高最高为 log2(n)log_2(n)

如果两点 rank 相等,只能增加树高,加 11(被合并树高+树根);否则,一定是不增加的(用秩小的指向秩大的)。

END

这是并查集可视化。





本文作者:Yurchiu

本文链接:https://yz-hs.github.io/3cd18e9c0ede/

版权声明:本博客中所有原创文章除特别声明外,均允许规范转载,转载请注明出处。所有非原创文章,按照原作者要求转载。


By Yurchiu.
其他物件杂物收纳
Hitokoto

Yurchiu 说,除了她以外的人都很强!嘤嘤嘤~~
博客信息
文章数目
158
最近更新
08-21
本站字数
350.6k
文章目录