当前位置:   article > 正文

数据结构与算法分析-C++描述 第8章 不相交集类(disjointSet)

disjointset

背景介绍(background):

       等价关系(equivalence relation):是满足下列三个性质的关系R:

               1)自反性:对所有的a\in S, a \ R \ a;(其中R表示关系);

               2)对称性:a \ R \ b 当且仅当b\ R \ a;   

               3)传递性:若a \ R \ bb \ R \ ca\ R \ c

               举例: a \leq b不具有等价性;电气连通性具有等价性。

       输入数据最初是N个集合的类(collection),每个集合含有一个元素,初始的所有关系均为false(除自反性),每个元素都有一个不同的元素,从而S_i \ \cap \ s_j = \o,这使得这些元素不相交;

不相交集类(disjointSet):

        不相交集类是将一些元素合并为不相交的各个集合,在同一个集合中的元素两两等价,不同集合中的元素不等价。此时,有两种操作是允许的:

        find:返回给定元素的集合的名字;

        union:如果想添加关系a \sim b,首先看二者是否存在关系(这可通过find检测二者是否在同一个类中),如果二者不在同一类中则对二者做union操作,将二者合并为一个新的等价类;

       该算法是动态的,因为在算法的执行过程中,集合可以通过union改变而改变。

动态等价性问题解决方案:

        1)保证指令find能够以常数最坏情形运行时间运行;

        2)保证指令union能够以常数最坏情况运行时间运行;

       已经证明二者不能同时以常数最坏情况运行时间运行;

基本数据结构:

        

       

 

非显示表示结果: 

 灵巧求并算法:

        1)按大小求并:对其进行简单的改进是借助任意的方法打破现在的随意性,使得总是较小的树成为较大的树的子树。为了实现按大小合并的方法,需要记住每棵树的大小,可以让每个根元素包含它的树的大小的负值。合并的时候首先检查树的大小,将较小的树成为较大树的子树,新的树的大小为两棵树大小的和。

        2)按高度求并: 跟踪每棵树的高度而不是大小并执行合并使得浅的树成为深的树的子树。只有两棵深度相等的树求并的时候树的高度才增加(树的深度加1),为了实现按高度求并,需要记住每棵树的高度,可以让每个根元素包含它的树的高度的负值。只有合并的两棵树高度相等的时候才需要更新树的高度(根元素的值减去1)。

按大小求并和按高度求并的非显示表示(根节点的“更新”准则不同,其他节点性质一致):

不相交类实例: 

  1. //disjointSet.cpp
  2. #include<iostream>
  3. #include<vector>
  4. #include<iomanip>
  5. using namespace std;
  6. class DisjointSet{
  7. public:
  8. //DisjointSet constructor
  9. explicit DisjointSet(int n);
  10. //find value operation
  11. int find(int value) const;
  12. //union root2 to root1
  13. void unionSet(int root1, int root2);
  14. //union root2 to root1 by size
  15. void unionSetBySize(int root1, int root2);
  16. //union root2 to root1 by height
  17. void unionSetByHeight(int root1, int root2);
  18. //print the result
  19. void print();
  20. //reallocate s
  21. void init(){
  22. for(int i = 0; i < s.size(); i++){
  23. s[i] = -1;
  24. }
  25. };
  26. private:
  27. vector<int> s;
  28. };
  29. DisjointSet::DisjointSet(int n = 10):s(n){
  30. for(int i = 0; i < n; i++){
  31. s[i] = -1;
  32. }
  33. }
  34. int DisjointSet::find(int value) const{
  35. if(s[value] == -1){
  36. return value;
  37. }else{
  38. return find(s[value]);
  39. }
  40. }
  41. void DisjointSet::unionSet(int root1, int root2){
  42. s[root2] = root1;
  43. }
  44. void DisjointSet::unionSetBySize(int root1, int root2){
  45. if(s[root2] < s[root1]){ //size root2 is larger
  46. s[root2] += s[root1];
  47. s[root1] = root2;
  48. }else{ //size root1 is larger
  49. s[root1] += s[root2];
  50. s[root2] = root1;
  51. }
  52. }
  53. void DisjointSet::unionSetByHeight(int root1, int root2){
  54. if(s[root2] < s[root1]){ //root2 is deeper
  55. s[root1] = root2;
  56. }else if(s[root2] == s[root1]){ //the height is same
  57. s[root1]--;
  58. s[root2] = root1;
  59. }else{ //root1 is deeper
  60. s[root2] = root1;
  61. }
  62. }
  63. void DisjointSet::print(){
  64. cout << " the disjointSet info as follow " << endl;
  65. for(typename vector<int>::iterator itr = s.begin(); itr != s.end(); ++itr){
  66. cout << setw(4) << *itr << " ";
  67. }
  68. cout << endl;
  69. for(int i = 0; i < s.size(); i++){
  70. cout << setw(4) << i << " ";
  71. }
  72. cout << endl;
  73. }
  74. int main(){
  75. cout << "simple disjointSet : " << endl;
  76. DisjointSet disjointSet(8);
  77. disjointSet.unionSet(4, 5);
  78. disjointSet.unionSet(6, 7);
  79. disjointSet.unionSet(4, 6);
  80. disjointSet.unionSet(3, 4);
  81. disjointSet.print();
  82. /*for(int i = 0; i < disjointSet.s.size(); i++){
  83. cout << disjointSet.find(i) << " ";
  84. }
  85. cout << endl;*/
  86. cout << "union disjointSet by size : " << endl;
  87. disjointSet.init();
  88. disjointSet.unionSetBySize(4, 5);
  89. disjointSet.unionSetBySize(6, 7);
  90. disjointSet.unionSetBySize(4, 6);
  91. disjointSet.unionSetBySize(3, 4);
  92. disjointSet.print();
  93. /*for(int i = 0; i < disjointSet.s.size(); i++){
  94. cout << disjointSet.find(i) << " ";
  95. }
  96. cout << endl;*/
  97. cout << "union disjointSet by height : " << endl;
  98. disjointSet.init();
  99. disjointSet.unionSetByHeight(4, 5);
  100. disjointSet.unionSetByHeight(6, 7);
  101. disjointSet.unionSetByHeight(4, 6);
  102. disjointSet.unionSetByHeight(3, 4);
  103. disjointSet.print();
  104. /*for(int i = 0; i < disjointSet.s.size(); i++){
  105. cout << disjointSet.find(i) << " ";
  106. }
  107. cout << endl;*/
  108. cout << "done . " << endl;
  109. return 0;
  110. }

 运行结果:

  1. simple disjointSet :
  2. the disjointSet info as follow
  3. -1 -1 -1 -1 3 4 4 6
  4. 0 1 2 3 4 5 6 7
  5. union disjointSet by size :
  6. the disjointSet info as follow
  7. -1 -1 -1 4 -5 4 4 6
  8. 0 1 2 3 4 5 6 7
  9. union disjointSet by height :
  10. the disjointSet info as follow
  11. -1 -1 -1 4 -3 4 4 6
  12. 0 1 2 3 4 5 6 7
  13. done .

practice makes perfect !

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/557638
推荐阅读
相关标签
  

闽ICP备14008679号