zoukankan      html  css  js  c++  java
  • 我对并查集的一些理解与看法

    并查集是一种对集合的处理。一开始我并没有认真分析过这种数据结构。以为就是对一个数组中的元素的普通集合操作。

    我最初的实现方法是这样的;

    定义一个set数组表示集合

    定义一个element数组表示元素。

    set[i]为0表示该集合为空;

    element[i]表示该元素所处集合的位置。

    例如表示集合{1,3,5,7,9},{2,4},{6,8,10}

    set={1,1,1,0,0,0....};

    element={1,2,1,2,1,3,1,3,1,3};

    下面以杭电1232、1233为例;

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    int main()
    {
        int m,n,i,j,a[1005],v1,v2,set,b[1005],count;
        while(~scanf("%d",&n),n)
        {
            scanf("%d",&m);
            if(m==0)
            {
                printf("%d
    ",n-1);
                continue;
            }
            memset(a,0,sizeof(a));
            memset(b,0,sizeof(b));
            set=1;
            scanf("%d %d",&v1,&v2);
            a[v1]=set,a[v2]=set;
            set++;
            for(i=0;i<m-1;i++)
            {
                scanf("%d %d",&v1,&v2);
                if(a[v1]!=0&&a[v2]!=0&&a[v1]!=a[v2])
                {
                    int temp=a[v2];
                    for(j=1;j<=n;j++)
                    {
                        if(a[j]==temp) a[j]=a[v1];
                    }
                }
                else if(a[v1]&&a[v2]==0)
                {
                    a[v2]=a[v1];
                }
                else if(a[v1]==0&&a[v2])
                {
                    a[v1]=a[v2];
                }
                else if(a[v1]==0&&a[v2]==0)
                {
                    a[v1]=a[v2]=set;
                    set++;
                }
            }
            for(i=1,count=0;i<=n;i++)
            {
                if(a[i]==0) count++;
                else if(a[i]&&b[a[i]]==0)
                {
                    count++;
                    b[a[i]]=1;
                }
            }
            printf("%d
    ",count-1);
        }
    }


    我们可以发现这个算法的时间主要花在集合生成以及元素合并这一块;

    例如要将我们刚才所说的集合2与集合3合并;就要把element数组中集合2的元素都改成3;或者要把集合3中的元素改成2;

    这个算法的发杂性在一般情况下是线性的;


    而另一种并查集就与之高效的多。利用路径压缩。和树的方式将并查集巧妙地在一个数组中实现并且调理清晰;

    合并操作过程只是将树一棵树与另一棵树合并。在平摊意义下是常数级别的

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    int a[1005];
    int find(int x){return a[x]==x?x:a[x]=find(a[x]);}
    int main()
    {
        int m,n,i,j,v1,v2,count,x,y;
        while(~scanf("%d",&n),n)
        {
            scanf("%d",&m);
            for(i=1;i<=n;i++) a[i]=i;
            for(i=0;i<m;i++)
            {
                scanf("%d %d",&v1,&v2);
                x=find(v1);y=find(v2);
                if(x!=y) a[x]=y;
            }
            for(i=1,count=0;i<=n;i++) if(a[i]==i) count++;
            printf("%d
    ",count-1);
        }
    }


  • 相关阅读:
    mongodb 介绍
    mysql+mencached 大规模web应用程序首选
    Hadoop 安装部署
    Hadoop 快速入门
    盘点十大热门Linux服务器发行版
    NoSQL数据库探讨之一 - 为什么要用非关系数据库?
    也谈IT企业发展模式
    linux中的分区与格式化(五)
    linux文件系统维护(四)
    Meta标签详解(转)
  • 原文地址:https://www.cnblogs.com/leejuen/p/5547490.html
Copyright © 2011-2022 走看看