用父亲结点数组实现并查集

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef struct ufset *UFset;
 6 struct ufset
 7 {
 8     int parent[100001];
 9     int root[100001];
10 }UFS;
11 int s[100001],y[100001],d[10000],add;
12 int UFfind(int e,UFset U)
13 {
14     int i,j=e;
15     while(U->root[j]==0)
16     {
17         j=U->parent[j];
18     }
19     while(j!=e)
20     {
21         i=U->parent[e];
22         U->parent[e]=j;
23         e=i;
24     }
25     return j;
26 }
27 int UFunion(int i,int j,UFset U)
28 {
29         U->parent[j]+=U->parent[i];
30         U->root[i]=0;
31         U->parent[i]=j;
32         return j;
33 }
34 int main()
35 {
36     UFset UF;
37     UF=(UFset)malloc(sizeof(UFS));
38     int e,n,m,k,x,i,a,b,t1,t2;
39     scanf("%d %d",&n,&m);
40     for(e=1;e<=n+1;e++)
41     {
42         UF->parent[e]=1;
43         UF->root[e]=1;
44     }
45     for(i=0;i<m;i++)
46     {
47         scanf("%d %d",&a,&b);
48         t1=UFfind(a,UF);t2=UFfind(b,UF);
49         if(t1!=t2)
50         {
51             UFunion(t1,t2,UF);
52         }
53     }
54     int t=0; 
55     for(i=1;i<n+1;i++)
56     {
57         if(UF->root[i]==1)
58         {
59             s[t]=UF->parent[i];
60             y[t++]=i;
61         }        
62     }
63     sort(s,s+t);
64     add=k=0;
65     for(i=1;;i++)
66     {
67         if(add>=n)
68             break;
69         else
70         {
71             add+=s[t-i];
72             d[k++]=UFfind(y[t-i],UF);
73         }
74     }
75     printf("%d\n",k);
76     sort(d,d+k);
77     for(i=0;i<k;i++)
78     {
79         if(i<k-1)
80         printf("%d ",d[i]);
81         else
82             printf("%d\n",d[i]);
83     }
84     return 0;
85 }
View Code

 并查集结构简单。在数据结构作业大招秒杀和战争来了中有巧妙的运用

在下面所描述的改进的并查集结构中增加一个根节点数组root,用来记录树的根结点。
当元素e所在结点不是根节点时,root[e]=0,parent[e]=表示其父节点;当元素e所在结点是根节点
时,root[e]=1,parent[e]的值是树中结点的个数.

1 typedef struct ufset *UFset;
2 struct ufset
3 {
4     int parent[100];
5     int root[100];
6 }UFS;

UFfind(e.U)运算从元素e相应的结点走到树根处,找出所在集合的元素
加速并查集运算的另一的办法就是采用路径压缩技术,在执行UFfind时,实际是找到了从一个结点
到树根的一条路径。路径压缩技术就是把这条路上的所有结点都改为树根的儿子,实现路径压缩的最简单方法是
在这条路上走两次,第一次找到树根,第二次将路上所有结点的父节点都改为树根。

int UFfind(int e,UFset U)
{
    int i,j=e;
    while(U->root[j]==0)
    {
        j=U->parent[j];
    }
    while(j!=e)
    {
        i=U->parent[e];
        U->parent[e]=j;
        e=i;
    }
    return j;
}

在最坏情况下,合并可能使n个结点的数退化成一条链,在这种情下,对所有元素各执行
一次UFfind将耗时O(N*N) 。所以,尽管,UFunion只需要O(1)时间,当UFfind可能是总时间
耗费很大,为了克服这个缺点。可以做以下改进,使得每次UFind不超过O(longn)时间。在树
根中保存该树的结点数,每次合并时,总将小树合并到大树上。当一个结点从一棵树移到另
一颗数上时,这个节点到树根的距离就增加1,而这个节点所在的树的大小至少增加一倍。
于是并查集中每一个结点至多被移动O(longn)次,从而每个节点到树根的距离不会超过O(longn)。
所以每次UFfind运算只需要O(longn)时间。

int UFunion(int i,int j,UFset U)
{
    if(U->parent[i]<U->parent[j])
    {
        U->parent[j]+=U->parent[i];
        U->root[i]=0;
        U->parent[i]=j;
        return j;
    }
    else
    {
        U->parent[j]+=U->parent[i];
        U->root[j]=0;
        U->parent[j]=i;
        return i;
    }
}

 

posted @ 2013-12-02 00:50  陈泽泽  阅读(830)  评论(0编辑  收藏  举报