【数据结构】并查集

来源:互联网 发布:纳粹德国知乎 编辑:程序博客网 时间:2024/06/02 06:36

并查集是一种高级数据结构,它能够在很短的时间内判断出两个节点是否属于同一个连通区域。一般来说,并查集有以下基本操作。


初始化

一开始每个节点都是独立的,互不相关,他们的祖先节点就是他们本身。

void  init(int n){for(int i=1;i<=n;i++){set[i]=i;//每个节点的祖先初始化为自身 }}

合并

比如Merge(A,B)将B的祖先的祖先设置为A的祖先,这样就把A的整个连通区域跟B的整个连通区域连接起来,也就是将A集合和B集合合并。

void union(int f1,int f2){f1=find(f1);f2=find(f2);if(f1==f2)return;//如果两个节点祖先相同,不进行任何操作 set[f1]=f2;}

路径压缩

在合并操作之前,我们需要找到两个节点的祖先,那么,假如我以这样的顺序合并:Merge(n-1,n),Merge(n-2,n-1),……Merge(2,3),Merge(1,2),最终树形结构退化成链表,检索效率大大减低。这时,路径压缩的作用就体现出来了。在每一次查询祖先的过程中,我们将每个节点的祖先都直接设置为根节点,这样的话,以后的每次查找都只需要查找一次就可以找到,原本有很多层的树被压缩到了只有2层。路径压缩使得算法效率大大提高,而在实际应用中也是经常使用的。

void find(int k){if(set[k]==k)return k;set[k]=find(set[k]);//路径压缩return set[k]; }


poj1988 
题意:有N块方块,开始每堆都是一个方块,编号1到n,有两种操作:
M x y 把x所在堆拿起来叠到y所在堆上面。 C x:问方块x下面有多少个方块 。

这道题除了维护并查集之外,还要维护sum数组和under数组,sum数组记录每一堆一共有多少方块,若parent[a]==a ,则sum[a]表示a所在的堆的方块数目。under数组记录了第i个方块下面有多少个方块,under数组在堆合并和路径压缩的时候都要更新,具体看代码。

const int MAX=31000;int parent[MAX];int sum[MAX];int under[MAX];int GetParent(int a){if(parent[a]==a) return a;int t=GetParent(parent[a]);//暂时保存根节点的下标 under[a]+=under[parent[a]];//要认清楚这是一个递归函数,所以这个语句会从根节点开始往回回溯. parent[a]=t;//路径压缩 return parent[a]; }void Merge(int a,int b)//把b所在堆叠到a所在堆上去。 {int n;int pa=GetParent(a);int pb=GetParent(b);if(pa==pb) return ;parent[pb]=pa;under[pb]=sum[pa];//under[pb]赋值前一定是0,因为parent[pb]=pb,pb一定是原b所在堆最底下的 sum[pa]+=sum[pb];}void init(int n){for(int i=1;i<=n;i++){sum[i]=1;under[i]=0;parent[i]=i; }}