并查集

来源:互联网 发布:php 文件管理 代码 编辑:程序博客网 时间:2024/06/05 20:42
并查集是一种比较有用的数据结构,主要是用于解决将一些元素合并和查找元素在某个集合的操作,即union操作和findSet操作。
其中,利用有根树实现并查集的方法是普遍使用的方法,也是效率最优的方法。
在并查集一开始时,每个元素做为一个单独的集合,即每个都是只含有一个根的子树。
在合并的时候,主要是采用按秩合并。在开始时,每个元素的秩为0,随着合并秩发生变化。
其中包括makeSet方法,即初始化集合的方法。我们用p[i]表示元素i所属的集合的祖先(即此集合的标识),用rank[i]表示元素i的秩。
C++代码 复制代码
  1. //初始化并查集    
  2. void makeset(int i)   
  3. {   
  4.      p[i]=i;   
  5. }  

接着就是合并操作:
C++代码 复制代码
  1. //合并i和j    
  2. void union1(int i,int j)   
  3. {   
  4.      link(findSet(i),findSet(j));   
  5. }  

合并的方法,调用了link方法,link方法主要是根据元素的秩修改元素的集合标识,从而使得元素合并。
C++代码 复制代码
  1. //合并工作    
  2. void link(int i,int j)   
  3. {   
  4.      if(rank[i]>rank[j])   
  5.      {   
  6.           p[i]=p[j];    
  7.      }   
  8.      else  
  9.      {   
  10.           p[j]=p[i];   
  11.           if(i==j)   
  12.           {   
  13.               rank[j]=rank[j]+1;    
  14.           }    
  15.      }   
  16. }  

可以看到传给link方法的参数是findSet,这是什么方法呢?其实就是寻找元素i的祖先的方法,最终传给link合并的,其实是元素的祖先。故合并其实是祖先合并。
不过,判断元素属于哪个集合,只需用findSet找到它的祖先即可,元素即与其祖先在同一个集合中。
完整的代码如下:
C++代码 复制代码
  1. #include<iostream>   
  2. #define NMAX 101   
  3. using namespace std;   
  4. int p[NMAX],rank[NMAX];   
  5. //初始化   
  6. void init()   
  7. {   
  8.     int i=1;   
  9.     for(;i<=NMAX-1;i++)   
  10.     {   
  11.         p[i]=-1;   
  12.         rank[i]=0;    
  13.     }    
  14. }    
  15. //初始化并查集    
  16. void makeset(int i)   
  17. {   
  18.      p[i]=i;   
  19. }   
  20. //合并工作    
  21. void link(int i,int j)   
  22. {   
  23.      if(rank[i]>rank[j])   
  24.      {   
  25.           p[i]=p[j];    
  26.      }   
  27.      else  
  28.      {   
  29.           p[j]=p[i];   
  30.           if(i==j)   
  31.           {   
  32.               rank[j]=rank[j]+1;    
  33.           }    
  34.      }   
  35. }   
  36. //找i的祖先,即集合的代表    
  37. int findSet(int i)   
  38. {   
  39.      if(i!=p[i])   
  40.      {   
  41.          p[i]=findSet(p[i]);    
  42.      }    
  43.      return p[i];   
  44. }   
  45. //合并i和j    
  46. void union1(int i,int j)   
  47. {   
  48.      link(findSet(i),findSet(j));   
  49. }   
  50. int main()   
  51. {   
  52.   int k;   
  53.   init();   
  54.   for(k=1;k<=10;k++)   
  55.   {   
  56.      makeset(k);    
  57.   }    
  58.   //<1,2>   
  59.   union1(1,2);   
  60.   //<3,4>   
  61.   union1(3,4);   
  62.   //<2,3>   
  63.   union1(2,3);   
  64.   //<6,7>   
  65.   union1(6,7);   
  66.   //<5,8>   
  67.   union1(5,8);   
  68.   //<9,10>   
  69.   union1(9,10);   
  70.   //<8,9>    
  71.   union1(8,9);   
  72.      
  73.   for(k=1;k<=10;k++)   
  74.   {   
  75.        printf("%d的集合为%d\n",k,findSet(k));    
  76.   }   
  77.      
  78.   system("pause");   
  79.   return 0;    
  80. }  

最终的输出为:
1的集合为1
2的集合为1
3的集合为1
4的集合为1
5的集合为5
6的集合为6
7的集合为6
8的集合为5
9的集合为5
10的集合为5