并查集—分离集合森林实现

来源:互联网 发布:音频dsp处理器数据 编辑:程序博客网 时间:2024/06/06 18:53
并查集总结


   今天总结一下并查集,这个完了之后,寒假学的数据结构基础的模板类的题目差不多就完了,对于模板题,敲上10遍、20遍、30遍,那么模板就不是模板,就成为了你自己的东西,就好像 A+B 一辈子也忘不了,以后每天敲一遍模板题,加深对模板的理解。


并查集,一般使用的是 数组实现、树实现,其中数组实现时间复杂度较高,树实现也就是分离集合森林 查找、合并的时间复杂度不会


超过 O(log2n)


n个人,m对有亲戚关系的

10 7

1 2

2 3

2 4 

3 4

5 6

6 7

8 9

初始化:{1}  {2}  {3}  {4} {5} {6} {7} {8}  {9}  {10}

初步合并 {1,2} {2,3} {2,4} {3,4} {5,6} {6,7} {8,9} {10}

最终合并 {1,2,3,4} {5,6,7} {8,9} {10}


分离集合森林如下:



一、树实现


并查集中,每一个集合代表一个分离集合树,多个集合形成一个森林,树根当做集合的代表,每一个节点都有一个父指针来表示附属关系,根节点指向自身,在一个树高度很低的树种查找一个节点所用的时间很少。所以 并查集的分离集合树的 开辟一个秩的int 数据来保证构造的分离集合树的高度较低,在合并的时候,让较小的秩的根指向较大秩的根,若俩个秩相等,任意一个指向另一个,并且它的秩+1;


POJ 2524 


#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>const int N= 50001;using namespace std;struct node{    int data; // 节点数据域    int zhi;  //秩 存放子树高度    int parent;//父节点}t[N];int n,m;int Find(int r)//查{    while(t[r].parent!=r)//判断双亲是不是自己    {        r = t[r].parent; //循环查找X,    }    /*     if(t[r].parent==r)  //递归实现        return r;    else        return (Find(t[r].parent));    */    int i=r,j;//压缩路径    while (t[i].parent!=r)//i的父亲不是r,进行压缩    {        j=t[i].parent;//记录i的父亲        t[i].parent=r;//改变i的父亲        i=j;//判断i的父亲    }    return r;}void Merge(int x,int y)//并:合并x y的子树{    x = Find(x);  //找x所在子树的编号    y = Find(y);    if(t[x].zhi>t[y].zhi) //较小秩 指向 较大秩        {            t[y].parent = x; //y链接到x上,x为父节点        }    else    {        t[x].parent = y;        if(t[x].zhi == t[y].zhi) //x连接y,y做为父节点            t[y].zhi++; //y的子树高度+1    }}void init(){    for(int i = 1;i<=n;i++)        {            t[i].data = i;            t[i].zhi = 0;//初始化 树高度为0            t[i].parent = i;//父节点是自己        }}int main(){    int x,y,l=0;    while(scanf("%d%d",&n,&m))    {        if(n==0 && m==0)            break;        l++;        init();        for(int i = 0;i<m;i++)        {            scanf("%d%d",&x,&y);            Merge(x,y);        }        int sum = 0;        for(int i = 1;i<=n;i++)        {            if(t[i].parent!=i)                sum++;        }        printf("Case %d: %d\n",l,n-sum);    }    return 0;}



   数组实现


#include <stdio.h>int bin[100010];int findx(int x){    int r=x;    while(bin[r] !=r)        r=bin[r];    return r;}void merge(int x,int y){    int fx,fy;    fx = findx(x);    fy = findx(y);    if(fx != fy)        bin[fx]=fy;}int main(){    int n,m,i,x,y,count;int t=1;    while(~scanf("%d%d",&n,&m))    {        if(n==0 && m == 0)            break;        for(i=1;i<=n;i++)            {                bin[i] = i;            }        for(i=1;i<=m;i++)        {            scanf("%d %d",&x,&y);            merge(x,y);        }        for(count = 0, i=1;i<=n;i++)            if(bin[i] == i)                count ++;        printf("Case %d: %d\n",t++,count);    }    return 0;} 


   
0 0