beckerjc@150: // -*- c++ -*- // beckerjc@218: #ifndef HUGO_UNION_FIND_H beckerjc@218: #define HUGO_UNION_FIND_H beckerjc@150: beckerjc@462: //!ingroup auxdat beckerjc@462: //!\file beckerjc@462: //!\brief Union-Find data structures. beckerjc@462: beckerjc@462: beckerjc@150: #include beckerjc@394: #include beckerjc@150: #include beckerjc@394: #include beckerjc@394: beckerjc@394: #include beckerjc@150: beckerjc@150: namespace hugo { beckerjc@150: beckerjc@462: //! \addtogroup auxdat beckerjc@462: //! @{ beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief A \e Union-Find data structure implementation beckerjc@462: * beckerjc@462: * The class implements the \e Union-Find data structure. beckerjc@462: * The union operation uses rank heuristic, while beckerjc@462: * the find operation uses path compresson. beckerjc@462: * This is a very simple but efficient implementation, providing beckerjc@462: * only four methods: join (union), find, insert and size. beckerjc@462: * For more features see the \ref UnionFindEnum class. beckerjc@462: * beckerjc@462: * \pre The elements are automatically added only if the map beckerjc@462: * given to the constructor was filled with -1's. Otherwise you beckerjc@462: * need to add all the elements by the \ref insert() method. beckerjc@462: */ beckerjc@462: beckerjc@150: template beckerjc@150: class UnionFind { beckerjc@150: beckerjc@150: public: beckerjc@150: typedef T ElementType; beckerjc@150: typedef std::pair PairType; beckerjc@150: beckerjc@150: private: beckerjc@150: std::vector data; beckerjc@150: TIntMap& map; beckerjc@150: beckerjc@150: public: beckerjc@150: UnionFind(TIntMap& m) : map(m) {} beckerjc@150: beckerjc@462: /** beckerjc@462: * \brief Returns the index of the element's component. beckerjc@462: * beckerjc@462: * The method returns the index of the element's component. beckerjc@462: * This is an integer between zero and the number of inserted elements. beckerjc@462: */ beckerjc@150: beckerjc@394: int find(T a) beckerjc@150: { beckerjc@349: int comp0 = map[a]; beckerjc@150: if (comp0 < 0) { beckerjc@394: return insert(a); beckerjc@150: } beckerjc@150: int comp = comp0; beckerjc@150: int next; beckerjc@150: while ( (next = data[comp].first) != comp) { beckerjc@150: comp = next; beckerjc@150: } beckerjc@150: while ( (next = data[comp0].first) != comp) { beckerjc@150: data[comp0].first = comp; beckerjc@150: comp0 = next; beckerjc@150: } beckerjc@150: beckerjc@150: return comp; beckerjc@150: } beckerjc@150: beckerjc@462: /** beckerjc@462: * \brief Insert a new element into the structure. beckerjc@462: * beckerjc@462: * This method inserts a new element into the data structure. beckerjc@462: * beckerjc@462: * It is not required to use this method: beckerjc@462: * if the map given to the constructor was filled beckerjc@462: * with -1's then it is called automatically beckerjc@462: * on the first \ref find or \ref join. beckerjc@462: * beckerjc@462: * The method returns the index of the new component. beckerjc@462: */ beckerjc@462: beckerjc@394: int insert(T a) beckerjc@150: { beckerjc@150: int n = data.size(); beckerjc@394: data.push_back(std::make_pair(n, 1)); beckerjc@150: map.set(a,n); beckerjc@150: return n; beckerjc@150: } beckerjc@150: beckerjc@462: /** beckerjc@462: * \brief Joining the components of element \e a and element \e b. beckerjc@462: * beckerjc@462: * This is the \e union operation of the Union-Find structure. beckerjc@462: * Joins the component of elemenent \e a and component of beckerjc@462: * element \e b. If \e a and \e b are in the same component then beckerjc@462: * it returns false otherwise it returns true. beckerjc@462: */ beckerjc@462: beckerjc@394: bool join(T a, T b) beckerjc@150: { beckerjc@394: int ca = find(a); beckerjc@394: int cb = find(b); beckerjc@150: beckerjc@150: if ( ca == cb ) beckerjc@150: return false; beckerjc@150: beckerjc@150: if ( data[ca].second > data[cb].second ) { beckerjc@150: data[cb].first = ca; beckerjc@150: data[ca].second += data[cb].second; beckerjc@150: } beckerjc@150: else { beckerjc@150: data[ca].first = cb; beckerjc@150: data[cb].second += data[ca].second; beckerjc@150: } beckerjc@150: return true; beckerjc@150: } beckerjc@150: beckerjc@462: /** beckerjc@462: * \brief Returns the size of the component of element \e a. beckerjc@462: * beckerjc@462: * Returns the size of the component of element \e a. beckerjc@462: */ beckerjc@462: beckerjc@394: int size(T a) beckerjc@218: { beckerjc@394: int ca = find(a); beckerjc@218: return data[ca].second; beckerjc@218: } beckerjc@218: beckerjc@150: }; beckerjc@150: beckerjc@394: beckerjc@394: beckerjc@394: beckerjc@394: /*******************************************************/ beckerjc@394: beckerjc@394: beckerjc@462: #ifdef DEVELOPMENT_DOCS beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief The auxiliary class for the \ref UnionFindEnum class. beckerjc@462: * beckerjc@462: * In the \ref UnionFindEnum class all components are represented as beckerjc@462: * a std::list. beckerjc@462: * Items of these lists are UnionFindEnumItem structures. beckerjc@462: * beckerjc@462: * The class has four fields: beckerjc@462: * - T me - the actual element beckerjc@462: * - IIter parent - the parent of the element in the union-find structure beckerjc@462: * - int size - the size of the component of the element. beckerjc@462: * Only valid if the element beckerjc@462: * is the leader of the component. beckerjc@462: * - CIter my_class - pointer into the list of components beckerjc@462: * pointing to the component of the element. beckerjc@462: * Only valid if the element is the leader of the component. beckerjc@462: */ beckerjc@462: beckerjc@462: #endif beckerjc@394: beckerjc@394: template beckerjc@394: struct UnionFindEnumItem { beckerjc@394: beckerjc@394: typedef std::list ItemList; beckerjc@394: typedef std::list ClassList; beckerjc@394: typedef typename ItemList::iterator IIter; beckerjc@394: typedef typename ClassList::iterator CIter; beckerjc@394: beckerjc@394: T me; beckerjc@394: IIter parent; beckerjc@394: int size; beckerjc@394: CIter my_class; beckerjc@394: beckerjc@394: UnionFindEnumItem() {} beckerjc@394: UnionFindEnumItem(const T &_me, CIter _my_class): beckerjc@394: me(_me), size(1), my_class(_my_class) {} beckerjc@394: }; beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief A \e Union-Find data structure implementation which beckerjc@462: * is able to enumerate the components. beckerjc@462: * beckerjc@462: * The class implements an \e Union-Find data structure beckerjc@462: * which is able to enumerate the components and the items in beckerjc@462: * a component. If you don't need this feature then perhaps it's beckerjc@462: * better to use the \ref UnionFind class which is more efficient. beckerjc@462: * beckerjc@462: * The union operation uses rank heuristic, while beckerjc@462: * the find operation uses path compresson. beckerjc@462: * beckerjc@462: * \pre You beckerjc@462: * need to add all the elements by the \ref insert() method. beckerjc@462: */ beckerjc@462: beckerjc@462: beckerjc@394: template class Map> beckerjc@394: class UnionFindEnum { beckerjc@394: beckerjc@394: typedef std::list > ItemList; beckerjc@394: typedef std::list ClassList; beckerjc@394: typedef typename ItemList::iterator IIter; beckerjc@394: typedef typename ItemList::const_iterator IcIter; beckerjc@394: typedef typename ClassList::iterator CIter; beckerjc@394: typedef typename ClassList::const_iterator CcIter; beckerjc@394: beckerjc@394: public: beckerjc@394: typedef T ElementType; beckerjc@394: typedef UnionFindEnumItem ItemType; beckerjc@394: typedef Map< IIter > MapType; beckerjc@394: beckerjc@394: private: beckerjc@394: MapType& m; beckerjc@394: ClassList classes; beckerjc@394: beckerjc@394: IIter _find(IIter a) const { beckerjc@394: IIter comp = a; beckerjc@394: IIter next; beckerjc@394: while( (next = comp->parent) != comp ) { beckerjc@394: comp = next; beckerjc@394: } beckerjc@394: beckerjc@394: IIter comp1 = a; beckerjc@394: while( (next = comp1->parent) != comp ) { beckerjc@394: comp1->parent = comp->parent; beckerjc@394: comp1 = next; beckerjc@394: } beckerjc@394: return comp; beckerjc@394: } beckerjc@394: beckerjc@394: public: beckerjc@394: UnionFindEnum(MapType& _m) : m(_m) {} beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Insert the given element into a new component. beckerjc@462: * beckerjc@462: * This method creates a new component consisting only of the beckerjc@462: * given element. beckerjc@462: */ beckerjc@462: beckerjc@394: void insert(const T &a) beckerjc@394: { beckerjc@394: beckerjc@394: beckerjc@394: classes.push_back(ItemList()); beckerjc@394: CIter aclass = classes.end(); beckerjc@394: --aclass; beckerjc@394: beckerjc@394: ItemList &alist = *aclass; beckerjc@394: alist.push_back(ItemType(a, aclass)); beckerjc@394: IIter ai = alist.begin(); beckerjc@394: beckerjc@394: ai->parent = ai; beckerjc@394: m.set(a, ai); beckerjc@394: beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Find the leader of the component of the given element. beckerjc@462: * beckerjc@462: * The method returns the leader of the component of the given element. beckerjc@462: */ beckerjc@462: beckerjc@394: T find(const T &a) const { beckerjc@394: return _find(m[a])->me; beckerjc@394: } beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Joining the component of element \e a and element \e b. beckerjc@462: * beckerjc@462: * This is the \e union operation of the Union-Find structure. beckerjc@462: * Joins the component of elemenent \e a and component of beckerjc@462: * element \e b. If \e a and \e b are in the same component then beckerjc@462: * returns false else returns true. beckerjc@462: */ beckerjc@462: beckerjc@394: bool join(T a, T b) { beckerjc@394: beckerjc@394: IIter ca = _find(m[a]); beckerjc@394: IIter cb = _find(m[b]); beckerjc@394: beckerjc@394: if ( ca == cb ) { beckerjc@394: return false; beckerjc@394: } beckerjc@394: beckerjc@394: if ( ca->size > cb->size ) { beckerjc@394: beckerjc@394: cb->parent = ca->parent; beckerjc@394: ca->size += cb->size; beckerjc@394: beckerjc@394: ItemList &alist = *ca->my_class; beckerjc@394: alist.splice(alist.end(),*cb->my_class); beckerjc@394: beckerjc@394: classes.erase(cb->my_class); beckerjc@394: cb->my_class = 0; beckerjc@394: } beckerjc@394: else { beckerjc@394: beckerjc@394: ca->parent = cb->parent; beckerjc@394: cb->size += ca->size; beckerjc@394: beckerjc@394: ItemList &blist = *cb->my_class; beckerjc@394: blist.splice(blist.end(),*ca->my_class); beckerjc@394: beckerjc@394: classes.erase(ca->my_class); beckerjc@394: ca->my_class = 0; beckerjc@394: } beckerjc@394: beckerjc@394: return true; beckerjc@394: } beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Returns the size of the component of element \e a. beckerjc@462: * beckerjc@462: * Returns the size of the component of element \e a. beckerjc@462: */ beckerjc@462: beckerjc@394: int size(const T &a) const { beckerjc@394: return _find(m[a])->size; beckerjc@394: } beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Split up the component of the element. beckerjc@462: * beckerjc@462: * Splitting the component of the element into sigleton beckerjc@462: * components (component of size one). beckerjc@462: */ beckerjc@462: beckerjc@394: void split(const T &a) { beckerjc@394: beckerjc@394: IIter ca = _find(m[a]); beckerjc@394: beckerjc@394: if ( ca->size == 1 ) beckerjc@394: return; beckerjc@394: beckerjc@394: CIter aclass = ca->my_class; beckerjc@394: beckerjc@394: for(IIter curr = ca; ++curr != aclass->end(); curr=ca) { beckerjc@394: classes.push_back(ItemList()); beckerjc@394: CIter nl = --classes.end(); beckerjc@394: nl->splice(nl->end(), *aclass, curr); beckerjc@394: beckerjc@394: curr->size=1; beckerjc@394: curr->parent=curr; beckerjc@394: curr->my_class = nl; beckerjc@394: } beckerjc@394: beckerjc@394: ca->size=1; beckerjc@394: return; beckerjc@394: } beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Set the given element to the leader element of its component. beckerjc@462: * beckerjc@462: * Set the given element to the leader element of its component. beckerjc@462: */ beckerjc@462: beckerjc@462: void makeRep(const T &a) { beckerjc@462: beckerjc@462: IIter ia = m[a]; beckerjc@462: IIter la = _find(ia); beckerjc@462: if (la == ia) return; beckerjc@462: beckerjc@462: ia->my_class = la->my_class; beckerjc@462: la->my_class = 0; beckerjc@462: beckerjc@462: ia->size = la->size; beckerjc@462: beckerjc@462: CIter l = ia->my_class; beckerjc@462: l->splice(l->begin(),*l,ia); beckerjc@462: beckerjc@462: ia->parent = ia; beckerjc@462: la->parent = ia; beckerjc@462: } beckerjc@462: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Remove the given element from the structure. beckerjc@462: * beckerjc@462: * Remove the given element from the structure. beckerjc@462: * beckerjc@462: * Removes the element from its component and if the component becomes beckerjc@462: * empty then removes that component from the component list. beckerjc@462: */ beckerjc@394: void erase(const T &a) { beckerjc@394: beckerjc@394: IIter ma = m[a]; beckerjc@394: if (ma == 0) return; beckerjc@394: beckerjc@394: IIter la = _find(ma); beckerjc@394: if (la == ma) { beckerjc@394: if (ma -> size == 1){ beckerjc@394: classes.erase(ma->my_class); beckerjc@394: m.set(a,0); beckerjc@394: return; beckerjc@394: } beckerjc@394: ++la; beckerjc@462: la->size = ma->size; beckerjc@394: la->my_class = ma->my_class; beckerjc@394: } beckerjc@394: beckerjc@394: for (IIter i = la; i != la->my_class->end(); ++i) { beckerjc@394: i->parent = la; beckerjc@394: } beckerjc@394: beckerjc@462: la->size--; beckerjc@394: la->my_class->erase(ma); beckerjc@394: m.set(a,0); beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Removes the component of the given element from the structure. beckerjc@462: * beckerjc@462: * Removes the component of the given element from the structure. beckerjc@462: */ beckerjc@462: beckerjc@394: void eraseClass(const T &a) { beckerjc@394: IIter ma = m[a]; beckerjc@394: if (ma == 0) return; beckerjc@394: # ifdef DEBUG beckerjc@394: CIter c = _find(ma)->my_class; beckerjc@394: for (IIter i=c->begin(); i!=c->end(); ++i) beckerjc@394: m.set(i->me, 0); beckerjc@394: # endif beckerjc@394: classes.erase(_find(ma)->my_class); beckerjc@394: } beckerjc@394: beckerjc@394: beckerjc@394: class ClassIt { beckerjc@394: friend class UnionFindEnum; beckerjc@394: beckerjc@394: CcIter i; beckerjc@394: public: beckerjc@394: ClassIt(Invalid): i(0) {} beckerjc@394: ClassIt() {} beckerjc@394: beckerjc@394: operator const T& () const { beckerjc@394: ItemList const &ll = *i; beckerjc@394: return (ll.begin())->me; } beckerjc@394: bool operator == (ClassIt it) const { beckerjc@394: return (i == it.i); beckerjc@394: } beckerjc@394: bool operator != (ClassIt it) const { beckerjc@394: return (i != it.i); beckerjc@394: } beckerjc@394: bool operator < (ClassIt it) const { beckerjc@394: return (i < it.i); beckerjc@394: } beckerjc@394: beckerjc@394: bool valid() const { return i != 0; } beckerjc@394: private: beckerjc@394: void first(const ClassList &l) { i = l.begin(); validate(l); } beckerjc@394: void next(const ClassList &l) { beckerjc@394: ++i; beckerjc@394: validate(l); beckerjc@394: } beckerjc@394: void validate(const ClassList &l) { beckerjc@394: if ( i == l.end() ) beckerjc@394: i = 0; beckerjc@394: } beckerjc@394: }; beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Sets the iterator to point to the first component. beckerjc@462: * beckerjc@462: * Sets the iterator to point to the first component. beckerjc@462: * beckerjc@462: * With the \ref first, \ref valid and \ref next methods you can beckerjc@462: * iterate through the components. For example: beckerjc@462: * \code beckerjc@462: * UnionFindEnum::MapType map(G); beckerjc@462: * UnionFindEnum U(map); beckerjc@462: * UnionFindEnum::ClassIt iter; beckerjc@462: * for (U.first(iter); U.valid(iter); U.next(iter)) { beckerjc@462: * // iter is convertible to Graph::Node beckerjc@462: * cout << iter << endl; beckerjc@462: * } beckerjc@462: * \endcode beckerjc@462: */ beckerjc@394: beckerjc@394: ClassIt& first(ClassIt& it) const { beckerjc@394: it.first(classes); beckerjc@394: return it; beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Returns whether the iterator is valid. beckerjc@462: * beckerjc@462: * Returns whether the iterator is valid. beckerjc@462: * beckerjc@462: * With the \ref first, \ref valid and \ref next methods you can beckerjc@462: * iterate through the components. See the example here: \ref first. beckerjc@462: */ beckerjc@462: beckerjc@394: bool valid(ClassIt const &it) const { beckerjc@394: return it.valid(); beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Steps the iterator to the next component. beckerjc@462: * beckerjc@462: * Steps the iterator to the next component. beckerjc@462: * beckerjc@462: * With the \ref first, \ref valid and \ref next methods you can beckerjc@462: * iterate through the components. See the example here: \ref first. beckerjc@462: */ beckerjc@462: beckerjc@394: ClassIt& next(ClassIt& it) const { beckerjc@394: it.next(classes); beckerjc@394: return it; beckerjc@394: } beckerjc@394: beckerjc@394: beckerjc@394: class ItemIt { beckerjc@394: friend class UnionFindEnum; beckerjc@394: beckerjc@394: IcIter i; beckerjc@394: const ItemList *l; beckerjc@394: public: beckerjc@394: ItemIt(Invalid): i(0) {} beckerjc@394: ItemIt() {} beckerjc@394: beckerjc@394: operator const T& () const { return i->me; } beckerjc@394: bool operator == (ItemIt it) const { beckerjc@394: return (i == it.i); beckerjc@394: } beckerjc@394: bool operator != (ItemIt it) const { beckerjc@394: return (i != it.i); beckerjc@394: } beckerjc@394: bool operator < (ItemIt it) const { beckerjc@394: return (i < it.i); beckerjc@394: } beckerjc@394: beckerjc@394: bool valid() const { return i != 0; } beckerjc@394: private: beckerjc@394: void first(const ItemList &il) { l=&il; i = l->begin(); validate(); } beckerjc@394: void next() { beckerjc@394: ++i; beckerjc@394: validate(); beckerjc@394: } beckerjc@394: void validate() { beckerjc@394: if ( i == l->end() ) beckerjc@394: i = 0; beckerjc@394: } beckerjc@394: }; beckerjc@394: beckerjc@394: beckerjc@462: beckerjc@462: /** beckerjc@462: * \brief Sets the iterator to point to the first element of the component. beckerjc@462: * beckerjc@462: * \anchor first2 beckerjc@462: * Sets the iterator to point to the first element of the component. beckerjc@462: * beckerjc@462: * With the \ref first2 "first", \ref valid2 "valid" beckerjc@462: * and \ref next2 "next" methods you can beckerjc@462: * iterate through the elements of a component. For example beckerjc@462: * (iterating through the component of the node \e node): beckerjc@462: * \code beckerjc@462: * Graph::Node node = ...; beckerjc@462: * UnionFindEnum::MapType map(G); beckerjc@462: * UnionFindEnum U(map); beckerjc@462: * UnionFindEnum::ItemIt iiter; beckerjc@462: * for (U.first(iiter, node); U.valid(iiter); U.next(iiter)) { beckerjc@462: * // iiter is convertible to Graph::Node beckerjc@462: * cout << iiter << endl; beckerjc@462: * } beckerjc@462: * \endcode beckerjc@462: */ beckerjc@462: beckerjc@394: ItemIt& first(ItemIt& it, const T& a) const { beckerjc@394: it.first( * _find(m[a])->my_class ); beckerjc@394: return it; beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Returns whether the iterator is valid. beckerjc@462: * beckerjc@462: * \anchor valid2 beckerjc@462: * Returns whether the iterator is valid. beckerjc@462: * beckerjc@462: * With the \ref first2 "first", \ref valid2 "valid" beckerjc@462: * and \ref next2 "next" methods you can beckerjc@462: * iterate through the elements of a component. beckerjc@462: * See the example here: \ref first2 "first". beckerjc@462: */ beckerjc@462: beckerjc@394: bool valid(ItemIt const &it) const { beckerjc@394: return it.valid(); beckerjc@394: } beckerjc@394: beckerjc@462: /** beckerjc@462: * \brief Steps the iterator to the next component. beckerjc@462: * beckerjc@462: * \anchor next2 beckerjc@462: * Steps the iterator to the next component. beckerjc@462: * beckerjc@462: * With the \ref first2 "first", \ref valid2 "valid" beckerjc@462: * and \ref next2 "next" methods you can beckerjc@462: * iterate through the elements of a component. beckerjc@462: * See the example here: \ref first2 "first". beckerjc@462: */ beckerjc@462: beckerjc@394: ItemIt& next(ItemIt& it) const { beckerjc@394: it.next(); beckerjc@394: return it; beckerjc@394: } beckerjc@394: beckerjc@462: }; beckerjc@394: beckerjc@394: beckerjc@462: //! @} beckerjc@394: beckerjc@150: } //namespace hugo beckerjc@150: beckerjc@218: #endif //HUGO_UNION_FIND_H