00001 //---------------------------------------------------------------------------- 00002 /** @file UnionFind.hpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef UNIONFIND_HPP 00007 #define UNIONFIND_HPP 00008 00009 #include <cassert> 00010 #include <vector> 00011 #include "Benzene.hpp" 00012 00013 _BEGIN_BENZENE_NAMESPACE_ 00014 00015 //---------------------------------------------------------------------------- 00016 00017 /** General union/find implementation. */ 00018 template<int S> 00019 class UnionFind 00020 { 00021 public: 00022 00023 /** Constructor. All elements are initially isolated. */ 00024 UnionFind(); 00025 00026 /** Sets all elements to be isolated. */ 00027 void Clear(); 00028 00029 /** Returns true if x is the captain of a group. */ 00030 bool IsRoot(int x) const; 00031 00032 /** Gets the captain of x's group. */ 00033 int GetRoot(int x) const; 00034 00035 /** Unions two sets of elements. */ 00036 int UnionGroups(int x, int y); 00037 00038 private: 00039 /** Flag denoting that the element is its own group. */ 00040 static const int ISOLATED = -1; 00041 00042 mutable std::vector<int> m_sets; 00043 }; 00044 00045 template<int S> 00046 inline UnionFind<S>::UnionFind() 00047 : m_sets(S) 00048 { 00049 Clear(); 00050 } 00051 00052 template<int S> 00053 inline void UnionFind<S>::Clear() 00054 { 00055 for (int i = 0; i < S; i++) 00056 m_sets[i] = ISOLATED; 00057 } 00058 00059 template<int S> 00060 inline bool UnionFind<S>::IsRoot(int x) const 00061 { 00062 return m_sets[x] < 0; 00063 } 00064 00065 template<int S> 00066 inline int UnionFind<S>::GetRoot(int x) const 00067 { 00068 assert(0 <= x && x < S); 00069 if (m_sets[x] < 0) 00070 return x; 00071 return (m_sets[x] = GetRoot(m_sets[x])); 00072 } 00073 00074 template<int S> 00075 inline int UnionFind<S>::UnionGroups(int a, int b) 00076 { 00077 int ra = GetRoot(a); 00078 int rb = GetRoot(b); 00079 if (ra == rb) 00080 return ra; 00081 // Force the smaller guy to become captain 00082 int cap = std::min(ra, rb); 00083 int non = std::max(ra, rb); 00084 m_sets[cap] += m_sets[non]; 00085 m_sets[non] = cap; 00086 return cap; 00087 } 00088 00089 //---------------------------------------------------------------------------- 00090 00091 _END_BENZENE_NAMESPACE_ 00092 00093 #endif // UNIONFIND_HPP