Advertisement
Nickpips

O(α(N)) for UnionFind operations?

Jun 15th, 2016
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.50 KB | None | 0 0
  1. #include <iostream>
  2. #include <unordered_map>
  3. #include <functional>
  4. #include <vector>
  5. #include <time.h>
  6. #include <map>
  7. #include <random>
  8.  
  9. using namespace std;
  10.  
  11. class UF
  12. {
  13. public:
  14.     UF()
  15.     {
  16.        
  17.     }
  18.     UF( int size )
  19.     {
  20.         parents.reserve(size);
  21.         ranks.reserve(size);
  22.         for( int i = 0; i < size; i++ )
  23.         {
  24.             parents.push_back(parents.size());
  25.             ranks.push_back(0);
  26.         }
  27.     }
  28.     void reserve( int size )
  29.     {
  30.         parents.reserve(size);
  31.         ranks.reserve(size);
  32.     }
  33.     int makeset()
  34.     {
  35.         int val = parents.size();
  36.         parents.push_back(val);
  37.         ranks.push_back(0);
  38.         return val;
  39.     }
  40.     bool sameset( int elem1, int elem2 )
  41.     {
  42.         if(elem1 >= parents.size() || elem2 >= parents.size() )
  43.         {
  44.             // ERR
  45.             return false;
  46.         }
  47.         return find(elem1) == find(elem2);
  48.     }
  49.     int find( int elem )
  50.     {
  51.         if(elem >= parents.size() )
  52.         {
  53.             // ERR
  54.             return -1;
  55.         }
  56.        
  57.         if( parents[elem] != elem )
  58.         {
  59.             parents[elem] = find( parents[elem] );
  60.         }
  61.         return parents[elem];
  62.     }
  63.     void merge( int elem1, int elem2 )
  64.     {
  65.         if(elem1 >= parents.size() || elem2 >= parents.size() )
  66.         {
  67.             // ERR
  68.             return;
  69.         }
  70.        
  71.         int root1 = find(elem1);
  72.         int root2 = find(elem2);
  73.        
  74.         if( root1 == root2 )
  75.             return;
  76.        
  77.         if( ranks[root1] < ranks[root2] )
  78.         {
  79.             parents[root1] = root2;
  80.         } else if( ranks[root2] < ranks[root1] )
  81.         {
  82.             parents[root2] = root1;
  83.         } else
  84.         {
  85.             parents[root2] = root1;
  86.             ranks[root1]++;
  87.         }
  88.     }
  89. private:
  90.     vector<int> parents;
  91.     vector<int> ranks;
  92. };
  93.  
  94. int main()
  95. {
  96.     int N = 10'000'000;
  97.     int M = 10'000'000;
  98.    
  99.     auto dice = bind ( uniform_int_distribution<int>(0,N-1), mt19937(random_device()()) );
  100.     UF unionfind;
  101.     clock_t t1;
  102.     clock_t t2;
  103.     vector<int> randnums(N+4*M);
  104.     for( int i = 0; i < randnums.size(); i++ )
  105.         randnums[i] = dice();
  106.     auto it = randnums.begin();
  107.    
  108.     t1 = clock();
  109.     for( int i = 0; i < N; i++ )
  110.         unionfind.makeset();
  111.     t2 = clock();
  112.     cout << "MAKESET: " << (t2-t1)/(float)CLOCKS_PER_SEC << endl;
  113.    
  114.     t1 = clock();
  115.     for( int i = 0; i < M; i++ )
  116.     {
  117.         unionfind.find( *(++it) );
  118.     }
  119.     t2 = clock();
  120.     cout << "FIND: " << (t2-t1)/(float)CLOCKS_PER_SEC << endl;
  121.    
  122.     t1 = clock();
  123.     for( int i = 0; i < M; i++ )
  124.     {
  125.         unionfind.merge( *(++it), *(++it) );
  126.     }
  127.     t2 = clock();
  128.     cout << "MERGE: " << (t2-t1)/(float)CLOCKS_PER_SEC << endl;
  129.    
  130.     t1 = clock();
  131.     for( int i = 0; i < M; i++ )
  132.     {
  133.         unionfind.find( *(++it) );
  134.     }
  135.     t2 = clock();
  136.     cout << "FIND AGAIN: " << (t2-t1)/(float)CLOCKS_PER_SEC << endl;
  137.    
  138.     t1 = clock();
  139.     for( int i = 0; i < M; i++ )
  140.     {
  141.         unionfind.find( *(++it) );
  142.     }
  143.     t2 = clock();
  144.     cout << "FIND AGAIN2: " << (t2-t1)/(float)CLOCKS_PER_SEC << endl;
  145.    
  146.     return 0;
  147. }
  148.  
  149. /*
  150. N = 100'000
  151. MAKESET: 0.001002
  152. FIND: 0.037006
  153. MERGE: 0.098528
  154. FIND AGAIN: 0.048562
  155. FIND AGAIN2: 0.000534
  156.  
  157. N = 1'000'000
  158. MAKESET: 0.011646
  159. FIND: 0.054282
  160. MERGE: 0.352768
  161. FIND AGAIN: 0.153535
  162. FIND AGAIN2: 0.012702
  163.  
  164. N = 10'000'000
  165. MAKESET: 0.16386
  166. FIND: 0.319329
  167. MERGE: 3.45287
  168. FIND AGAIN: 0.532275
  169. FIND AGAIN2: 0.472613
  170.  
  171. N = 1'000'000
  172. M = 1'000'000
  173. MAKESET: 0.010744
  174. FIND: 0.005321
  175. MERGE: 0.101198
  176. FIND AGAIN: 0.013164
  177. FIND AGAIN2: 0.009081
  178.  
  179. MAKESET should be O(N), the rest should be O(M α(N)), but this appears to not be the case.
  180. */
  181.  
  182. /* a more general Union-Find data structure, but unordered_map is super slow
  183. template <typename T>
  184. class UF
  185. {
  186. public:
  187.     UF<T>()
  188.     {
  189.        
  190.     }
  191.     UF<T>( const vector<T>& init )
  192.     {
  193.         compression.reserve(init.size());
  194.         parents.reserve(init.size());
  195.         ranks.reserve(init.size());
  196.         for( const T& i : init )
  197.         {
  198.             compression[i] = parents.size();
  199.             parents.push_back(parents.size());
  200.             ranks.push_back(0);
  201.         }
  202.     }
  203.     void reserve( int size )
  204.     {
  205.         compression.reserve(size);
  206.         parents.reserve(size);
  207.         ranks.reserve(size);
  208.     }
  209.     void makeset( const T& set )
  210.     {
  211.         if( compression.count(set) == 1 )
  212.             return; // Err, already exists
  213.         compression[set] = parents.size();
  214.         parents.push_back(parents.size());
  215.         ranks.push_back(0);
  216.     }
  217.     bool sameset( const T& set1, const T& set2 )
  218.     {
  219.         return find(set1) == find(set2);
  220.     }
  221.     int find( const T& set )
  222.     {
  223.         if( compression.count(set) == 0 )
  224.             return -1; // Err, not in set
  225.         return rawfind(compression[set]);
  226.     }
  227.     void merge( const T& set1, const T& set2 )
  228.     {
  229.         if( compression.count(set1) == 0 || compression.count(set2) == 0 )
  230.             return; // Err, not in set
  231.        
  232.         int comprSet1 = compression[set1];
  233.         int comprSet2 = compression[set2];
  234.        
  235.         int root1 = find(set1);
  236.         int root2 = find(set2);
  237.        
  238.         if( root1 == root2 )
  239.             return;
  240.        
  241.         if( ranks[root1] < ranks[root2] )
  242.         {
  243.             parents[root1] = root2;
  244.         } else if( ranks[root2] < ranks[root1] )
  245.         {
  246.             parents[root2] = root1;
  247.         } else
  248.         {
  249.             parents[root2] = root1;
  250.             ranks[root1]++;
  251.         }
  252.     }
  253.     void print()
  254.     {
  255.         cout << "[ ";
  256.         for( auto it = compression.begin(); it != compression.end(); it++ )
  257.         {
  258.             auto it2 = it;
  259.             it2++;
  260.             cout << "(" << it->first << ":" << it->second << ")" << (it2 == compression.end() ? " " : ", ");
  261.         }
  262.         cout << "]\n";
  263.         printArr(parents);
  264.         printArr(ranks);
  265.     }
  266. private:
  267.     void printArr( const vector<int>& arr )
  268.     {
  269.         cout << "[ ";
  270.         for( auto it = arr.begin(); it != arr.end(); it++ )
  271.         {
  272.             cout << *it << (it + 1 == arr.end() ? " " : ", ");
  273.         }
  274.         cout << "]\n";
  275.     }
  276.     int rawfind( const int set )
  277.     {
  278.         if( parents[set] != set )
  279.             parents[set] = rawfind( parents[set] );
  280.         return parents[set];
  281.     }
  282.     unordered_map<T,int> compression;
  283.     vector<int> parents;
  284.     vector<int> ranks;
  285. };
  286. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement