diff -r d8475431bbbb -r 8e85e6bbefdf lemon/unionfind.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/unionfind.h Mon May 23 04:48:14 2005 +0000 @@ -0,0 +1,724 @@ +/* -*- C++ -*- + * lemon/unionfind.h - Part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_UNION_FIND_H +#define LEMON_UNION_FIND_H + +//!\ingroup auxdat +//!\file +//!\brief Union-Find data structures. +//! +//!\bug unionfind_test.cc doesn't work with Intel compiler. It compiles but +//!fails to run (Segmentation fault). + + +#include +#include +#include +#include + +#include + +namespace lemon { + + //! \addtogroup auxdat + //! @{ + + /** + * \brief A \e Union-Find data structure implementation + * + * The class implements the \e Union-Find data structure. + * The union operation uses rank heuristic, while + * the find operation uses path compression. + * This is a very simple but efficient implementation, providing + * only four methods: join (union), find, insert and size. + * For more features see the \ref UnionFindEnum class. + * + * It is primarily used in Kruskal algorithm for finding minimal + * cost spanning tree in a graph. + * \sa kruskal() + * + * \pre The elements are automatically added only if the map + * given to the constructor was filled with -1's. Otherwise you + * need to add all the elements by the \ref insert() method. + * \bug It is not clear what the constructor parameter is used for. + */ + + template + class UnionFind { + + public: + typedef T ElementType; + typedef std::pair PairType; + + private: + std::vector data; + TIntMap& map; + + public: + UnionFind(TIntMap& m) : map(m) {} + + /** + * \brief Returns the index of the element's component. + * + * The method returns the index of the element's component. + * This is an integer between zero and the number of inserted elements. + */ + + int find(T a) + { + int comp0 = map[a]; + if (comp0 < 0) { + return insert(a); + } + int comp = comp0; + int next; + while ( (next = data[comp].first) != comp) { + comp = next; + } + while ( (next = data[comp0].first) != comp) { + data[comp0].first = comp; + comp0 = next; + } + + return comp; + } + + /** + * \brief Inserts a new element into the structure. + * + * This method inserts a new element into the data structure. + * + * It is not required to use this method: + * if the map given to the constructor was filled + * with -1's then it is called automatically + * on the first \ref find or \ref join. + * + * The method returns the index of the new component. + */ + + int insert(T a) + { + int n = data.size(); + data.push_back(std::make_pair(n, 1)); + map.set(a,n); + return n; + } + + /** + * \brief Joining the components of element \e a and element \e b. + * + * This is the \e union operation of the Union-Find structure. + * Joins the component of element \e a and component of + * element \e b. If \e a and \e b are in the same component then + * it returns false otherwise it returns true. + */ + + bool join(T a, T b) + { + int ca = find(a); + int cb = find(b); + + if ( ca == cb ) + return false; + + if ( data[ca].second > data[cb].second ) { + data[cb].first = ca; + data[ca].second += data[cb].second; + } + else { + data[ca].first = cb; + data[cb].second += data[ca].second; + } + return true; + } + + /** + * \brief Returns the size of the component of element \e a. + * + * Returns the size of the component of element \e a. + */ + + int size(T a) + { + int ca = find(a); + return data[ca].second; + } + + }; + + + + + /*******************************************************/ + + +#ifdef DEVELOPMENT_DOCS + + /** + * \brief The auxiliary class for the \ref UnionFindEnum class. + * + * In the \ref UnionFindEnum class all components are represented as + * a std::list. + * Items of these lists are UnionFindEnumItem structures. + * + * The class has four fields: + * - T me - the actual element + * - IIter parent - the parent of the element in the union-find structure + * - int size - the size of the component of the element. + * Only valid if the element + * is the leader of the component. + * - CIter my_class - pointer into the list of components + * pointing to the component of the element. + * Only valid if the element is the leader of the component. + */ + +#endif + + template + struct UnionFindEnumItem { + + typedef std::list ItemList; + typedef std::list ClassList; + typedef typename ItemList::iterator IIter; + typedef typename ClassList::iterator CIter; + + T me; + IIter parent; + int size; + CIter my_class; + + UnionFindEnumItem() {} + UnionFindEnumItem(const T &_me, CIter _my_class): + me(_me), size(1), my_class(_my_class) {} + }; + + + /** + * \brief A \e Union-Find data structure implementation which + * is able to enumerate the components. + * + * The class implements a \e Union-Find data structure + * which is able to enumerate the components and the items in + * a component. If you don't need this feature then perhaps it's + * better to use the \ref UnionFind class which is more efficient. + * + * The union operation uses rank heuristic, while + * the find operation uses path compression. + * + * \pre You + * need to add all the elements by the \ref insert() method. + */ + + + template class Map> + class UnionFindEnum { + + typedef std::list > ItemList; + typedef std::list ClassList; + typedef typename ItemList::iterator IIter; + typedef typename ItemList::const_iterator IcIter; + typedef typename ClassList::iterator CIter; + typedef typename ClassList::const_iterator CcIter; + + public: + typedef T ElementType; + typedef UnionFindEnumItem ItemType; + typedef Map< IIter > MapType; + + private: + MapType& m; + ClassList classes; + + IIter _find(IIter a) const { + IIter comp = a; + IIter next; + while( (next = comp->parent) != comp ) { + comp = next; + } + + IIter comp1 = a; + while( (next = comp1->parent) != comp ) { + comp1->parent = comp->parent; + comp1 = next; + } + return comp; + } + + public: + UnionFindEnum(MapType& _m) : m(_m) {} + + + /** + * \brief Inserts the given element into a new component. + * + * This method creates a new component consisting only of the + * given element. + */ + + void insert(const T &a) + { + + + classes.push_back(ItemList()); + CIter aclass = classes.end(); + --aclass; + + ItemList &alist = *aclass; + alist.push_back(ItemType(a, aclass)); + IIter ai = alist.begin(); + + ai->parent = ai; + m.set(a, ai); + + } + + /** + * \brief Inserts the given element into the component of the others. + * + * This methods inserts the element \e a into the component of the + * element \e comp. + */ + + void insert(const T &a, const T &comp) { + + IIter clit = _find(m[comp]); + ItemList &c = *clit->my_class; + c.push_back(ItemType(a,0)); + IIter ai = c.end(); + --ai; + ai->parent = clit; + m.set(a, ai); + ++clit->size; + } + + + /** + * \brief Finds the leader of the component of the given element. + * + * The method returns the leader of the component of the given element. + */ + + T find(const T &a) const { + return _find(m[a])->me; + } + + + /** + * \brief Joining the component of element \e a and element \e b. + * + * This is the \e union operation of the Union-Find structure. + * Joins the component of element \e a and component of + * element \e b. If \e a and \e b are in the same component then + * returns false else returns true. + */ + + bool join(T a, T b) { + + IIter ca = _find(m[a]); + IIter cb = _find(m[b]); + + if ( ca == cb ) { + return false; + } + + if ( ca->size > cb->size ) { + + cb->parent = ca->parent; + ca->size += cb->size; + + ItemList &alist = *ca->my_class; + alist.splice(alist.end(),*cb->my_class); + + classes.erase(cb->my_class); + cb->my_class = 0; + } + else { + + ca->parent = cb->parent; + cb->size += ca->size; + + ItemList &blist = *cb->my_class; + blist.splice(blist.end(),*ca->my_class); + + classes.erase(ca->my_class); + ca->my_class = 0; + } + + return true; + } + + + /** + * \brief Returns the size of the component of element \e a. + * + * Returns the size of the component of element \e a. + */ + + int size(const T &a) const { + return _find(m[a])->size; + } + + + /** + * \brief Splits up the component of the element. + * + * Splitting the component of the element into sigleton + * components (component of size one). + */ + + void split(const T &a) { + + IIter ca = _find(m[a]); + + if ( ca->size == 1 ) + return; + + CIter aclass = ca->my_class; + + for(IIter curr = ca; ++curr != aclass->end(); curr=ca) { + classes.push_back(ItemList()); + CIter nl = --classes.end(); + nl->splice(nl->end(), *aclass, curr); + + curr->size=1; + curr->parent=curr; + curr->my_class = nl; + } + + ca->size=1; + return; + } + + + /** + * \brief Sets the given element to the leader element of its component. + * + * Sets the given element to the leader element of its component. + */ + + void makeRep(const T &a) { + + IIter ia = m[a]; + IIter la = _find(ia); + if (la == ia) return; + + ia->my_class = la->my_class; + la->my_class = 0; + + ia->size = la->size; + + CIter l = ia->my_class; + l->splice(l->begin(),*l,ia); + + ia->parent = ia; + la->parent = ia; + } + + /** + * \brief Moves the given element to an other component. + * + * This method moves the element \e a from its component + * to the component of \e comp. + * If \e a and \e comp are in the same component then + * it returns false otherwise it returns true. + */ + + bool move(const T &a, const T &comp) { + + IIter ai = m[a]; + IIter lai = _find(ai); + IIter clit = _find(m[comp]); + + if (lai == clit) + return false; + + ItemList &cl = *clit->my_class, + &al = *lai->my_class; + + bool is_leader = (lai == ai); + bool singleton = false; + + if (is_leader) { + ++lai; + } + + cl.splice(cl.end(), al, ai); + + if (is_leader) { + if (ai->size == 1) { + classes.erase(ai->my_class); + singleton = true; + } + else { + lai->size = ai->size; + lai->my_class = ai->my_class; + } + } + if (!singleton) { + for (IIter i = lai; i != al.end(); ++i) + i->parent = lai; + --lai->size; + } + + ai->parent = clit; + ai->my_class = 0; + ++clit->size; + + return true; + } + + + /** + * \brief Removes the given element from the structure. + * + * Removes the given element from the structure. + * + * Removes the element from its component and if the component becomes + * empty then removes that component from the component list. + */ + void erase(const T &a) { + + IIter ma = m[a]; + if (ma == 0) return; + + IIter la = _find(ma); + if (la == ma) { + if (ma -> size == 1){ + classes.erase(ma->my_class); + m.set(a,0); + return; + } + ++la; + la->size = ma->size; + la->my_class = ma->my_class; + } + + for (IIter i = la; i != la->my_class->end(); ++i) { + i->parent = la; + } + + la->size--; + la->my_class->erase(ma); + m.set(a,0); + } + + /** + * \brief Removes the component of the given element from the structure. + * + * Removes the component of the given element from the structure. + */ + + void eraseClass(const T &a) { + IIter ma = m[a]; + if (ma == 0) return; +# ifdef DEBUG + CIter c = _find(ma)->my_class; + for (IIter i=c->begin(); i!=c->end(); ++i) + m.set(i->me, 0); +# endif + classes.erase(_find(ma)->my_class); + } + + + class ClassIt { + friend class UnionFindEnum; + + CcIter i; + public: + ClassIt(Invalid): i(0) {} + ClassIt() {} + + operator const T& () const { + ItemList const &ll = *i; + return (ll.begin())->me; } + bool operator == (ClassIt it) const { + return (i == it.i); + } + bool operator != (ClassIt it) const { + return (i != it.i); + } + bool operator < (ClassIt it) const { + return (i < it.i); + } + + bool valid() const { return i != 0; } + private: + void first(const ClassList &l) { i = l.begin(); validate(l); } + void next(const ClassList &l) { + ++i; + validate(l); + } + void validate(const ClassList &l) { + if ( i == l.end() ) + i = 0; + } + }; + + /** + * \brief Sets the iterator to point to the first component. + * + * Sets the iterator to point to the first component. + * + * With the \ref first, \ref valid and \ref next methods you can + * iterate through the components. For example: + * \code + * UnionFindEnum::MapType map(G); + * UnionFindEnum U(map); + * UnionFindEnum::ClassIt iter; + * for (U.first(iter); U.valid(iter); U.next(iter)) { + * // iter is convertible to Graph::Node + * cout << iter << endl; + * } + * \endcode + */ + + ClassIt& first(ClassIt& it) const { + it.first(classes); + return it; + } + + /** + * \brief Returns whether the iterator is valid. + * + * Returns whether the iterator is valid. + * + * With the \ref first, \ref valid and \ref next methods you can + * iterate through the components. See the example here: \ref first. + */ + + bool valid(ClassIt const &it) const { + return it.valid(); + } + + /** + * \brief Steps the iterator to the next component. + * + * Steps the iterator to the next component. + * + * With the \ref first, \ref valid and \ref next methods you can + * iterate through the components. See the example here: \ref first. + */ + + ClassIt& next(ClassIt& it) const { + it.next(classes); + return it; + } + + + class ItemIt { + friend class UnionFindEnum; + + IcIter i; + const ItemList *l; + public: + ItemIt(Invalid): i(0) {} + ItemIt() {} + + operator const T& () const { return i->me; } + bool operator == (ItemIt it) const { + return (i == it.i); + } + bool operator != (ItemIt it) const { + return (i != it.i); + } + bool operator < (ItemIt it) const { + return (i < it.i); + } + + bool valid() const { return i != 0; } + private: + void first(const ItemList &il) { l=&il; i = l->begin(); validate(); } + void next() { + ++i; + validate(); + } + void validate() { + if ( i == l->end() ) + i = 0; + } + }; + + + + /** + * \brief Sets the iterator to point to the first element of the component. + * + * \anchor first2 + * Sets the iterator to point to the first element of the component. + * + * With the \ref first2 "first", \ref valid2 "valid" + * and \ref next2 "next" methods you can + * iterate through the elements of a component. For example + * (iterating through the component of the node \e node): + * \code + * Graph::Node node = ...; + * UnionFindEnum::MapType map(G); + * UnionFindEnum U(map); + * UnionFindEnum::ItemIt iiter; + * for (U.first(iiter, node); U.valid(iiter); U.next(iiter)) { + * // iiter is convertible to Graph::Node + * cout << iiter << endl; + * } + * \endcode + */ + + ItemIt& first(ItemIt& it, const T& a) const { + it.first( * _find(m[a])->my_class ); + return it; + } + + /** + * \brief Returns whether the iterator is valid. + * + * \anchor valid2 + * Returns whether the iterator is valid. + * + * With the \ref first2 "first", \ref valid2 "valid" + * and \ref next2 "next" methods you can + * iterate through the elements of a component. + * See the example here: \ref first2 "first". + */ + + bool valid(ItemIt const &it) const { + return it.valid(); + } + + /** + * \brief Steps the iterator to the next component. + * + * \anchor next2 + * Steps the iterator to the next component. + * + * With the \ref first2 "first", \ref valid2 "valid" + * and \ref next2 "next" methods you can + * iterate through the elements of a component. + * See the example here: \ref first2 "first". + */ + + ItemIt& next(ItemIt& it) const { + it.next(); + return it; + } + + }; + + + //! @} + +} //namespace lemon + +#endif //LEMON_UNION_FIND_H