alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@103: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. alpar@103: * alpar@103: * Copyright (C) 2003-2008 alpar@103: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@103: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@103: * alpar@103: * Permission to use, modify and distribute this software is granted alpar@103: * provided that this copyright notice appears in all copies. For alpar@103: * precise terms see the accompanying LICENSE file. alpar@103: * alpar@103: * This software is provided "AS IS" with no warranty of any kind, alpar@103: * express or implied, and with no claim as to its suitability for any alpar@103: * purpose. alpar@103: * alpar@103: */ alpar@103: alpar@103: #ifndef LEMON_UNION_FIND_H alpar@103: #define LEMON_UNION_FIND_H alpar@103: alpar@103: //!\ingroup auxdat alpar@103: //!\file alpar@103: //!\brief Union-Find data structures. alpar@103: //! alpar@103: alpar@103: #include alpar@103: #include alpar@103: #include alpar@103: #include alpar@103: #include alpar@103: deba@220: #include alpar@103: alpar@103: namespace lemon { alpar@103: alpar@103: /// \ingroup auxdat alpar@103: /// alpar@103: /// \brief A \e Union-Find data structure implementation alpar@103: /// alpar@209: /// The class implements the \e Union-Find data structure. alpar@103: /// The union operation uses rank heuristic, while alpar@103: /// the find operation uses path compression. alpar@209: /// This is a very simple but efficient implementation, providing alpar@103: /// only four methods: join (union), find, insert and size. alpar@103: /// For more features see the \ref UnionFindEnum class. alpar@103: /// alpar@103: /// It is primarily used in Kruskal algorithm for finding minimal alpar@103: /// cost spanning tree in a graph. alpar@103: /// \sa kruskal() alpar@103: /// alpar@103: /// \pre You need to add all the elements by the \ref insert() alpar@209: /// method. alpar@103: template alpar@103: class UnionFind { alpar@103: public: alpar@103: alpar@103: typedef _ItemIntMap ItemIntMap; alpar@103: typedef typename ItemIntMap::Key Item; alpar@103: alpar@103: private: alpar@103: // If the items vector stores negative value for an item then alpar@103: // that item is root item and it has -items[it] component size. alpar@103: // Else the items[it] contains the index of the parent. alpar@103: std::vector items; alpar@103: ItemIntMap& index; alpar@103: alpar@103: bool rep(int idx) const { alpar@103: return items[idx] < 0; alpar@103: } alpar@103: alpar@103: int repIndex(int idx) const { alpar@103: int k = idx; alpar@103: while (!rep(k)) { alpar@103: k = items[k] ; alpar@103: } alpar@103: while (idx != k) { alpar@103: int next = items[idx]; alpar@103: const_cast(items[idx]) = k; alpar@103: idx = next; alpar@103: } alpar@103: return k; alpar@103: } alpar@103: alpar@103: public: alpar@103: alpar@103: /// \brief Constructor alpar@103: /// alpar@103: /// Constructor of the UnionFind class. You should give an item to alpar@103: /// integer map which will be used from the data structure. If you alpar@103: /// modify directly this map that may cause segmentation fault, alpar@103: /// invalid data structure, or infinite loop when you use again alpar@103: /// the union-find. alpar@103: UnionFind(ItemIntMap& m) : index(m) {} alpar@103: alpar@103: /// \brief Returns the index of the element's component. alpar@103: /// alpar@103: /// The method returns the index of the element's component. alpar@103: /// This is an integer between zero and the number of inserted elements. alpar@103: /// alpar@103: int find(const Item& a) { alpar@103: return repIndex(index[a]); alpar@103: } alpar@103: alpar@103: /// \brief Clears the union-find data structure alpar@103: /// alpar@103: /// Erase each item from the data structure. alpar@103: void clear() { alpar@103: items.clear(); alpar@103: } alpar@103: alpar@103: /// \brief Inserts a new element into the structure. alpar@103: /// alpar@209: /// This method inserts a new element into the data structure. alpar@103: /// alpar@103: /// The method returns the index of the new component. alpar@103: int insert(const Item& a) { alpar@103: int n = items.size(); alpar@103: items.push_back(-1); alpar@103: index.set(a,n); alpar@103: return n; alpar@103: } alpar@103: alpar@103: /// \brief Joining the components of element \e a and element \e b. alpar@103: /// alpar@209: /// This is the \e union operation of the Union-Find structure. alpar@103: /// Joins the component of element \e a and component of alpar@103: /// element \e b. If \e a and \e b are in the same component then alpar@103: /// it returns false otherwise it returns true. alpar@103: bool join(const Item& a, const Item& b) { alpar@103: int ka = repIndex(index[a]); alpar@103: int kb = repIndex(index[b]); alpar@103: alpar@209: if ( ka == kb ) alpar@209: return false; alpar@103: alpar@103: if (items[ka] < items[kb]) { alpar@209: items[ka] += items[kb]; alpar@209: items[kb] = ka; alpar@103: } else { alpar@209: items[kb] += items[ka]; alpar@209: items[ka] = kb; alpar@103: } alpar@103: return true; alpar@103: } alpar@103: alpar@103: /// \brief Returns the size of the component of element \e a. alpar@103: /// alpar@103: /// Returns the size of the component of element \e a. alpar@103: int size(const Item& a) { alpar@103: int k = repIndex(index[a]); alpar@103: return - items[k]; alpar@103: } alpar@103: alpar@103: }; alpar@103: alpar@103: /// \ingroup auxdat alpar@103: /// alpar@103: /// \brief A \e Union-Find data structure implementation which alpar@103: /// is able to enumerate the components. alpar@103: /// alpar@103: /// The class implements a \e Union-Find data structure alpar@103: /// which is able to enumerate the components and the items in alpar@103: /// a component. If you don't need this feature then perhaps it's alpar@103: /// better to use the \ref UnionFind class which is more efficient. alpar@103: /// alpar@103: /// The union operation uses rank heuristic, while alpar@103: /// the find operation uses path compression. alpar@103: /// alpar@103: /// \pre You need to add all the elements by the \ref insert() alpar@103: /// method. alpar@103: /// alpar@103: template alpar@103: class UnionFindEnum { alpar@103: public: alpar@209: alpar@103: typedef _ItemIntMap ItemIntMap; alpar@103: typedef typename ItemIntMap::Key Item; alpar@103: alpar@103: private: alpar@209: alpar@103: ItemIntMap& index; alpar@103: alpar@103: // If the parent stores negative value for an item then that item alpar@103: // is root item and it has ~(items[it].parent) component id. Else alpar@103: // the items[it].parent contains the index of the parent. alpar@103: // alpar@103: // The \c next and \c prev provides the double-linked alpar@103: // cyclic list of one component's items. alpar@103: struct ItemT { alpar@103: int parent; alpar@103: Item item; alpar@103: alpar@103: int next, prev; alpar@103: }; alpar@103: alpar@103: std::vector items; alpar@103: int firstFreeItem; alpar@103: alpar@103: struct ClassT { alpar@103: int size; alpar@103: int firstItem; alpar@103: int next, prev; alpar@103: }; alpar@209: alpar@103: std::vector classes; alpar@103: int firstClass, firstFreeClass; alpar@103: alpar@103: int newClass() { alpar@103: if (firstFreeClass == -1) { alpar@209: int cdx = classes.size(); alpar@209: classes.push_back(ClassT()); alpar@209: return cdx; alpar@103: } else { alpar@209: int cdx = firstFreeClass; alpar@209: firstFreeClass = classes[firstFreeClass].next; alpar@209: return cdx; alpar@103: } alpar@103: } alpar@103: alpar@103: int newItem() { alpar@103: if (firstFreeItem == -1) { alpar@209: int idx = items.size(); alpar@209: items.push_back(ItemT()); alpar@209: return idx; alpar@103: } else { alpar@209: int idx = firstFreeItem; alpar@209: firstFreeItem = items[firstFreeItem].next; alpar@209: return idx; alpar@103: } alpar@103: } alpar@103: alpar@103: alpar@103: bool rep(int idx) const { alpar@103: return items[idx].parent < 0; alpar@103: } alpar@103: alpar@103: int repIndex(int idx) const { alpar@103: int k = idx; alpar@103: while (!rep(k)) { alpar@103: k = items[k].parent; alpar@103: } alpar@103: while (idx != k) { alpar@103: int next = items[idx].parent; alpar@103: const_cast(items[idx].parent) = k; alpar@103: idx = next; alpar@103: } alpar@103: return k; alpar@103: } alpar@103: alpar@103: int classIndex(int idx) const { alpar@103: return ~(items[repIndex(idx)].parent); alpar@103: } alpar@103: alpar@103: void singletonItem(int idx) { alpar@103: items[idx].next = idx; alpar@103: items[idx].prev = idx; alpar@103: } alpar@103: alpar@103: void laceItem(int idx, int rdx) { alpar@103: items[idx].prev = rdx; alpar@103: items[idx].next = items[rdx].next; alpar@103: items[items[rdx].next].prev = idx; alpar@103: items[rdx].next = idx; alpar@103: } alpar@103: alpar@103: void unlaceItem(int idx) { alpar@103: items[items[idx].prev].next = items[idx].next; alpar@103: items[items[idx].next].prev = items[idx].prev; alpar@209: alpar@103: items[idx].next = firstFreeItem; alpar@103: firstFreeItem = idx; alpar@103: } alpar@103: alpar@103: void spliceItems(int ak, int bk) { alpar@103: items[items[ak].prev].next = bk; alpar@103: items[items[bk].prev].next = ak; alpar@103: int tmp = items[ak].prev; alpar@103: items[ak].prev = items[bk].prev; alpar@103: items[bk].prev = tmp; alpar@209: alpar@103: } alpar@103: alpar@103: void laceClass(int cls) { alpar@103: if (firstClass != -1) { alpar@103: classes[firstClass].prev = cls; alpar@103: } alpar@103: classes[cls].next = firstClass; alpar@103: classes[cls].prev = -1; alpar@103: firstClass = cls; alpar@209: } alpar@103: alpar@103: void unlaceClass(int cls) { alpar@103: if (classes[cls].prev != -1) { alpar@103: classes[classes[cls].prev].next = classes[cls].next; alpar@103: } else { alpar@103: firstClass = classes[cls].next; alpar@103: } alpar@103: if (classes[cls].next != -1) { alpar@103: classes[classes[cls].next].prev = classes[cls].prev; alpar@103: } alpar@209: alpar@103: classes[cls].next = firstFreeClass; alpar@103: firstFreeClass = cls; alpar@209: } alpar@103: alpar@103: public: alpar@103: alpar@209: UnionFindEnum(ItemIntMap& _index) alpar@209: : index(_index), items(), firstFreeItem(-1), alpar@209: firstClass(-1), firstFreeClass(-1) {} alpar@209: alpar@103: /// \brief Inserts the given element into a new component. alpar@103: /// alpar@103: /// This method creates a new component consisting only of the alpar@103: /// given element. alpar@103: /// alpar@103: int insert(const Item& item) { alpar@103: int idx = newItem(); alpar@103: alpar@103: index.set(item, idx); alpar@103: alpar@103: singletonItem(idx); alpar@103: items[idx].item = item; alpar@103: alpar@103: int cdx = newClass(); alpar@103: alpar@103: items[idx].parent = ~cdx; alpar@103: alpar@103: laceClass(cdx); alpar@103: classes[cdx].size = 1; alpar@103: classes[cdx].firstItem = idx; alpar@103: alpar@103: firstClass = cdx; alpar@209: alpar@103: return cdx; alpar@103: } alpar@103: alpar@103: /// \brief Inserts the given element into the component of the others. alpar@103: /// alpar@103: /// This methods inserts the element \e a into the component of the alpar@209: /// element \e comp. alpar@103: void insert(const Item& item, int cls) { alpar@103: int rdx = classes[cls].firstItem; alpar@103: int idx = newItem(); alpar@103: alpar@103: index.set(item, idx); alpar@103: alpar@103: laceItem(idx, rdx); alpar@103: alpar@103: items[idx].item = item; alpar@103: items[idx].parent = rdx; alpar@103: alpar@103: ++classes[~(items[rdx].parent)].size; alpar@103: } alpar@103: alpar@103: /// \brief Clears the union-find data structure alpar@103: /// alpar@103: /// Erase each item from the data structure. alpar@103: void clear() { alpar@103: items.clear(); alpar@103: firstClass = -1; alpar@103: firstFreeItem = -1; alpar@103: } alpar@103: alpar@103: /// \brief Finds the component of the given element. alpar@103: /// alpar@103: /// The method returns the component id of the given element. alpar@103: int find(const Item &item) const { alpar@103: return ~(items[repIndex(index[item])].parent); alpar@103: } alpar@103: alpar@103: /// \brief Joining the component of element \e a and element \e b. alpar@103: /// alpar@209: /// This is the \e union operation of the Union-Find structure. alpar@103: /// Joins the component of element \e a and component of alpar@103: /// element \e b. If \e a and \e b are in the same component then alpar@103: /// returns -1 else returns the remaining class. alpar@103: int join(const Item& a, const Item& b) { alpar@103: alpar@103: int ak = repIndex(index[a]); alpar@103: int bk = repIndex(index[b]); alpar@103: alpar@103: if (ak == bk) { alpar@209: return -1; alpar@103: } alpar@103: alpar@103: int acx = ~(items[ak].parent); alpar@103: int bcx = ~(items[bk].parent); alpar@103: alpar@103: int rcx; alpar@103: alpar@103: if (classes[acx].size > classes[bcx].size) { alpar@209: classes[acx].size += classes[bcx].size; alpar@209: items[bk].parent = ak; alpar@103: unlaceClass(bcx); alpar@209: rcx = acx; alpar@103: } else { alpar@209: classes[bcx].size += classes[acx].size; alpar@209: items[ak].parent = bk; alpar@103: unlaceClass(acx); alpar@209: rcx = bcx; alpar@103: } alpar@103: spliceItems(ak, bk); alpar@103: alpar@103: return rcx; alpar@103: } alpar@103: alpar@103: /// \brief Returns the size of the class. alpar@103: /// alpar@103: /// Returns the size of the class. alpar@103: int size(int cls) const { alpar@103: return classes[cls].size; alpar@103: } alpar@103: alpar@209: /// \brief Splits up the component. alpar@103: /// alpar@103: /// Splitting the component into singleton components (component alpar@103: /// of size one). alpar@103: void split(int cls) { alpar@103: int fdx = classes[cls].firstItem; alpar@103: int idx = items[fdx].next; alpar@103: while (idx != fdx) { alpar@103: int next = items[idx].next; alpar@103: alpar@209: singletonItem(idx); alpar@103: alpar@209: int cdx = newClass(); alpar@103: items[idx].parent = ~cdx; alpar@103: alpar@209: laceClass(cdx); alpar@209: classes[cdx].size = 1; alpar@209: classes[cdx].firstItem = idx; alpar@209: alpar@103: idx = next; alpar@103: } alpar@103: alpar@103: items[idx].prev = idx; alpar@103: items[idx].next = idx; alpar@103: alpar@103: classes[~(items[idx].parent)].size = 1; alpar@209: alpar@103: } alpar@103: alpar@103: /// \brief Removes the given element from the structure. alpar@103: /// alpar@103: /// Removes the element from its component and if the component becomes alpar@103: /// empty then removes that component from the component list. alpar@103: /// alpar@103: /// \warning It is an error to remove an element which is not in alpar@103: /// the structure. alpar@103: /// \warning This running time of this operation is proportional to the alpar@103: /// number of the items in this class. alpar@103: void erase(const Item& item) { alpar@103: int idx = index[item]; alpar@103: int fdx = items[idx].next; alpar@103: alpar@103: int cdx = classIndex(idx); alpar@103: if (idx == fdx) { alpar@209: unlaceClass(cdx); alpar@209: items[idx].next = firstFreeItem; alpar@209: firstFreeItem = idx; alpar@209: return; alpar@103: } else { alpar@209: classes[cdx].firstItem = fdx; alpar@209: --classes[cdx].size; alpar@209: items[fdx].parent = ~cdx; alpar@103: alpar@209: unlaceItem(idx); alpar@209: idx = items[fdx].next; alpar@209: while (idx != fdx) { alpar@209: items[idx].parent = fdx; alpar@209: idx = items[idx].next; alpar@209: } alpar@209: alpar@103: } alpar@103: alpar@103: } alpar@103: alpar@103: /// \brief Gives back a representant item of the component. alpar@103: /// alpar@103: /// Gives back a representant item of the component. alpar@103: Item item(int cls) const { alpar@103: return items[classes[cls].firstItem].item; alpar@103: } alpar@103: alpar@103: /// \brief Removes the component of the given element from the structure. alpar@103: /// alpar@103: /// Removes the component of the given element from the structure. alpar@103: /// alpar@103: /// \warning It is an error to give an element which is not in the alpar@103: /// structure. alpar@103: void eraseClass(int cls) { alpar@103: int fdx = classes[cls].firstItem; alpar@103: unlaceClass(cls); alpar@103: items[items[fdx].prev].next = firstFreeItem; alpar@103: firstFreeItem = fdx; alpar@103: } alpar@103: ladanyi@236: /// \brief LEMON style iterator for the representant items. alpar@103: /// alpar@103: /// ClassIt is a lemon style iterator for the components. It iterates alpar@103: /// on the ids of the classes. alpar@103: class ClassIt { alpar@103: public: alpar@103: /// \brief Constructor of the iterator alpar@103: /// alpar@103: /// Constructor of the iterator alpar@103: ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) { alpar@103: cdx = unionFind->firstClass; alpar@103: } alpar@103: alpar@103: /// \brief Constructor to get invalid iterator alpar@103: /// alpar@103: /// Constructor to get invalid iterator alpar@103: ClassIt(Invalid) : unionFind(0), cdx(-1) {} alpar@209: alpar@103: /// \brief Increment operator alpar@103: /// alpar@103: /// It steps to the next representant item. alpar@103: ClassIt& operator++() { alpar@103: cdx = unionFind->classes[cdx].next; alpar@103: return *this; alpar@103: } alpar@209: alpar@103: /// \brief Conversion operator alpar@103: /// alpar@103: /// It converts the iterator to the current representant item. alpar@103: operator int() const { alpar@103: return cdx; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ClassIt& i) { alpar@103: return i.cdx == cdx; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ClassIt& i) { alpar@103: return i.cdx != cdx; alpar@103: } alpar@209: alpar@103: private: alpar@103: const UnionFindEnum* unionFind; alpar@103: int cdx; alpar@103: }; alpar@103: ladanyi@236: /// \brief LEMON style iterator for the items of a component. alpar@103: /// alpar@103: /// ClassIt is a lemon style iterator for the components. It iterates alpar@103: /// on the items of a class. By example if you want to iterate on alpar@103: /// each items of each classes then you may write the next code. alpar@103: ///\code alpar@103: /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { alpar@103: /// std::cout << "Class: "; alpar@103: /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { alpar@103: /// std::cout << toString(iit) << ' ' << std::endl; alpar@103: /// } alpar@103: /// std::cout << std::endl; alpar@103: /// } alpar@103: ///\endcode alpar@103: class ItemIt { alpar@103: public: alpar@103: /// \brief Constructor of the iterator alpar@103: /// alpar@103: /// Constructor of the iterator. The iterator iterates alpar@103: /// on the class of the \c item. alpar@103: ItemIt(const UnionFindEnum& ufe, int cls) : unionFind(&ufe) { alpar@103: fdx = idx = unionFind->classes[cls].firstItem; alpar@103: } alpar@103: alpar@103: /// \brief Constructor to get invalid iterator alpar@103: /// alpar@103: /// Constructor to get invalid iterator alpar@103: ItemIt(Invalid) : unionFind(0), idx(-1) {} alpar@209: alpar@103: /// \brief Increment operator alpar@103: /// alpar@103: /// It steps to the next item in the class. alpar@103: ItemIt& operator++() { alpar@103: idx = unionFind->items[idx].next; alpar@103: if (idx == fdx) idx = -1; alpar@103: return *this; alpar@103: } alpar@209: alpar@103: /// \brief Conversion operator alpar@103: /// alpar@103: /// It converts the iterator to the current item. alpar@103: operator const Item&() const { alpar@103: return unionFind->items[idx].item; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ItemIt& i) { alpar@103: return i.idx == idx; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ItemIt& i) { alpar@103: return i.idx != idx; alpar@103: } alpar@209: alpar@103: private: alpar@103: const UnionFindEnum* unionFind; alpar@103: int idx, fdx; alpar@103: }; alpar@103: alpar@103: }; alpar@103: alpar@103: /// \ingroup auxdat alpar@103: /// alpar@103: /// \brief A \e Extend-Find data structure implementation which alpar@103: /// is able to enumerate the components. alpar@103: /// alpar@103: /// The class implements an \e Extend-Find data structure which is alpar@103: /// able to enumerate the components and the items in a alpar@103: /// component. The data structure is a simplification of the alpar@103: /// Union-Find structure, and it does not allow to merge two components. alpar@103: /// alpar@103: /// \pre You need to add all the elements by the \ref insert() alpar@103: /// method. alpar@103: template alpar@103: class ExtendFindEnum { alpar@103: public: alpar@209: alpar@103: typedef _ItemIntMap ItemIntMap; alpar@103: typedef typename ItemIntMap::Key Item; alpar@103: alpar@103: private: alpar@209: alpar@103: ItemIntMap& index; alpar@103: alpar@103: struct ItemT { alpar@103: int cls; alpar@103: Item item; alpar@103: int next, prev; alpar@103: }; alpar@103: alpar@103: std::vector items; alpar@103: int firstFreeItem; alpar@103: alpar@103: struct ClassT { alpar@103: int firstItem; alpar@103: int next, prev; alpar@103: }; alpar@103: alpar@103: std::vector classes; alpar@103: alpar@103: int firstClass, firstFreeClass; alpar@103: alpar@103: int newClass() { alpar@103: if (firstFreeClass != -1) { alpar@209: int cdx = firstFreeClass; alpar@209: firstFreeClass = classes[cdx].next; alpar@209: return cdx; alpar@103: } else { alpar@209: classes.push_back(ClassT()); alpar@209: return classes.size() - 1; alpar@103: } alpar@103: } alpar@103: alpar@103: int newItem() { alpar@103: if (firstFreeItem != -1) { alpar@209: int idx = firstFreeItem; alpar@209: firstFreeItem = items[idx].next; alpar@209: return idx; alpar@103: } else { alpar@209: items.push_back(ItemT()); alpar@209: return items.size() - 1; alpar@103: } alpar@103: } alpar@103: alpar@103: public: alpar@103: alpar@103: /// \brief Constructor alpar@209: ExtendFindEnum(ItemIntMap& _index) alpar@209: : index(_index), items(), firstFreeItem(-1), alpar@209: classes(), firstClass(-1), firstFreeClass(-1) {} alpar@209: alpar@103: /// \brief Inserts the given element into a new component. alpar@103: /// alpar@103: /// This method creates a new component consisting only of the alpar@103: /// given element. alpar@103: int insert(const Item& item) { alpar@103: int cdx = newClass(); alpar@103: classes[cdx].prev = -1; alpar@103: classes[cdx].next = firstClass; alpar@103: if (firstClass != -1) { alpar@209: classes[firstClass].prev = cdx; alpar@103: } alpar@103: firstClass = cdx; alpar@209: alpar@103: int idx = newItem(); alpar@103: items[idx].item = item; alpar@103: items[idx].cls = cdx; alpar@103: items[idx].prev = idx; alpar@103: items[idx].next = idx; alpar@103: alpar@103: classes[cdx].firstItem = idx; alpar@103: alpar@103: index.set(item, idx); alpar@209: alpar@103: return cdx; alpar@103: } alpar@103: alpar@103: /// \brief Inserts the given element into the given component. alpar@103: /// alpar@103: /// This methods inserts the element \e item a into the \e cls class. alpar@103: void insert(const Item& item, int cls) { alpar@103: int idx = newItem(); alpar@103: int rdx = classes[cls].firstItem; alpar@103: items[idx].item = item; alpar@103: items[idx].cls = cls; alpar@103: alpar@103: items[idx].prev = rdx; alpar@103: items[idx].next = items[rdx].next; alpar@103: items[items[rdx].next].prev = idx; alpar@103: items[rdx].next = idx; alpar@103: alpar@103: index.set(item, idx); alpar@103: } alpar@103: alpar@103: /// \brief Clears the union-find data structure alpar@103: /// alpar@103: /// Erase each item from the data structure. alpar@103: void clear() { alpar@103: items.clear(); alpar@103: classes.clear; alpar@103: firstClass = firstFreeClass = firstFreeItem = -1; alpar@103: } alpar@103: alpar@103: /// \brief Gives back the class of the \e item. alpar@103: /// alpar@103: /// Gives back the class of the \e item. alpar@103: int find(const Item &item) const { alpar@103: return items[index[item]].cls; alpar@103: } alpar@103: alpar@103: /// \brief Gives back a representant item of the component. alpar@103: /// alpar@103: /// Gives back a representant item of the component. alpar@103: Item item(int cls) const { alpar@103: return items[classes[cls].firstItem].item; alpar@103: } alpar@209: alpar@103: /// \brief Removes the given element from the structure. alpar@103: /// alpar@103: /// Removes the element from its component and if the component becomes alpar@103: /// empty then removes that component from the component list. alpar@103: /// alpar@103: /// \warning It is an error to remove an element which is not in alpar@103: /// the structure. alpar@103: void erase(const Item &item) { alpar@103: int idx = index[item]; alpar@103: int cdx = items[idx].cls; alpar@209: alpar@103: if (idx == items[idx].next) { alpar@209: if (classes[cdx].prev != -1) { alpar@209: classes[classes[cdx].prev].next = classes[cdx].next; alpar@209: } else { alpar@209: firstClass = classes[cdx].next; alpar@209: } alpar@209: if (classes[cdx].next != -1) { alpar@209: classes[classes[cdx].next].prev = classes[cdx].prev; alpar@209: } alpar@209: classes[cdx].next = firstFreeClass; alpar@209: firstFreeClass = cdx; alpar@103: } else { alpar@209: classes[cdx].firstItem = items[idx].next; alpar@209: items[items[idx].next].prev = items[idx].prev; alpar@209: items[items[idx].prev].next = items[idx].next; alpar@103: } alpar@103: items[idx].next = firstFreeItem; alpar@103: firstFreeItem = idx; alpar@103: alpar@209: } alpar@209: alpar@209: alpar@103: /// \brief Removes the component of the given element from the structure. alpar@103: /// alpar@103: /// Removes the component of the given element from the structure. alpar@103: /// alpar@103: /// \warning It is an error to give an element which is not in the alpar@103: /// structure. alpar@103: void eraseClass(int cdx) { alpar@103: int idx = classes[cdx].firstItem; alpar@103: items[items[idx].prev].next = firstFreeItem; alpar@103: firstFreeItem = idx; alpar@103: alpar@103: if (classes[cdx].prev != -1) { alpar@209: classes[classes[cdx].prev].next = classes[cdx].next; alpar@103: } else { alpar@209: firstClass = classes[cdx].next; alpar@103: } alpar@103: if (classes[cdx].next != -1) { alpar@209: classes[classes[cdx].next].prev = classes[cdx].prev; alpar@103: } alpar@103: classes[cdx].next = firstFreeClass; alpar@103: firstFreeClass = cdx; alpar@103: } alpar@103: ladanyi@236: /// \brief LEMON style iterator for the classes. alpar@103: /// alpar@103: /// ClassIt is a lemon style iterator for the components. It iterates alpar@103: /// on the ids of classes. alpar@103: class ClassIt { alpar@103: public: alpar@103: /// \brief Constructor of the iterator alpar@103: /// alpar@103: /// Constructor of the iterator alpar@103: ClassIt(const ExtendFindEnum& ufe) : extendFind(&ufe) { alpar@103: cdx = extendFind->firstClass; alpar@103: } alpar@103: alpar@103: /// \brief Constructor to get invalid iterator alpar@103: /// alpar@103: /// Constructor to get invalid iterator alpar@103: ClassIt(Invalid) : extendFind(0), cdx(-1) {} alpar@209: alpar@103: /// \brief Increment operator alpar@103: /// alpar@103: /// It steps to the next representant item. alpar@103: ClassIt& operator++() { alpar@103: cdx = extendFind->classes[cdx].next; alpar@103: return *this; alpar@103: } alpar@209: alpar@103: /// \brief Conversion operator alpar@103: /// alpar@103: /// It converts the iterator to the current class id. alpar@103: operator int() const { alpar@103: return cdx; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ClassIt& i) { alpar@103: return i.cdx == cdx; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ClassIt& i) { alpar@103: return i.cdx != cdx; alpar@103: } alpar@209: alpar@103: private: alpar@103: const ExtendFindEnum* extendFind; alpar@103: int cdx; alpar@103: }; alpar@103: ladanyi@236: /// \brief LEMON style iterator for the items of a component. alpar@103: /// alpar@103: /// ClassIt is a lemon style iterator for the components. It iterates alpar@103: /// on the items of a class. By example if you want to iterate on alpar@103: /// each items of each classes then you may write the next code. alpar@103: ///\code alpar@103: /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { alpar@103: /// std::cout << "Class: "; alpar@103: /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { alpar@103: /// std::cout << toString(iit) << ' ' << std::endl; alpar@103: /// } alpar@103: /// std::cout << std::endl; alpar@103: /// } alpar@103: ///\endcode alpar@103: class ItemIt { alpar@103: public: alpar@103: /// \brief Constructor of the iterator alpar@103: /// alpar@103: /// Constructor of the iterator. The iterator iterates alpar@103: /// on the class of the \c item. alpar@103: ItemIt(const ExtendFindEnum& ufe, int cls) : extendFind(&ufe) { alpar@103: fdx = idx = extendFind->classes[cls].firstItem; alpar@103: } alpar@103: alpar@103: /// \brief Constructor to get invalid iterator alpar@103: /// alpar@103: /// Constructor to get invalid iterator alpar@103: ItemIt(Invalid) : extendFind(0), idx(-1) {} alpar@209: alpar@103: /// \brief Increment operator alpar@103: /// alpar@103: /// It steps to the next item in the class. alpar@103: ItemIt& operator++() { alpar@103: idx = extendFind->items[idx].next; alpar@209: if (fdx == idx) idx = -1; alpar@103: return *this; alpar@103: } alpar@209: alpar@103: /// \brief Conversion operator alpar@103: /// alpar@103: /// It converts the iterator to the current item. alpar@103: operator const Item&() const { alpar@103: return extendFind->items[idx].item; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ItemIt& i) { alpar@103: return i.idx == idx; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ItemIt& i) { alpar@103: return i.idx != idx; alpar@103: } alpar@209: alpar@103: private: alpar@103: const ExtendFindEnum* extendFind; alpar@103: int idx, fdx; alpar@103: }; alpar@103: alpar@103: }; alpar@103: alpar@103: /// \ingroup auxdat alpar@103: /// alpar@103: /// \brief A \e Union-Find data structure implementation which alpar@103: /// is able to store a priority for each item and retrieve the minimum of alpar@103: /// each class. alpar@103: /// alpar@103: /// A \e Union-Find data structure implementation which is able to alpar@103: /// store a priority for each item and retrieve the minimum of each alpar@103: /// class. In addition, it supports the joining and splitting the alpar@103: /// components. If you don't need this feature then you makes alpar@103: /// better to use the \ref UnionFind class which is more efficient. alpar@103: /// alpar@103: /// The union-find data strcuture based on a (2, 16)-tree with a alpar@103: /// tournament minimum selection on the internal nodes. The insert alpar@103: /// operation takes O(1), the find, set, decrease and increase takes alpar@103: /// O(log(n)), where n is the number of nodes in the current alpar@103: /// component. The complexity of join and split is O(log(n)*k), alpar@103: /// where n is the sum of the number of the nodes and k is the alpar@103: /// number of joined components or the number of the components alpar@103: /// after the split. alpar@103: /// alpar@103: /// \pre You need to add all the elements by the \ref insert() alpar@103: /// method. alpar@103: /// alpar@209: template > alpar@103: class HeapUnionFind { alpar@103: public: alpar@209: alpar@103: typedef _Value Value; alpar@103: typedef typename _ItemIntMap::Key Item; alpar@103: alpar@103: typedef _ItemIntMap ItemIntMap; alpar@103: alpar@103: typedef _Comp Comp; alpar@103: alpar@103: private: alpar@103: alpar@103: static const int cmax = 16; alpar@103: alpar@103: ItemIntMap& index; alpar@103: alpar@103: struct ClassNode { alpar@103: int parent; alpar@103: int depth; alpar@103: alpar@103: int left, right; alpar@103: int next, prev; alpar@103: }; alpar@103: alpar@103: int first_class; alpar@103: int first_free_class; alpar@103: std::vector classes; alpar@103: alpar@103: int newClass() { alpar@103: if (first_free_class < 0) { alpar@103: int id = classes.size(); alpar@103: classes.push_back(ClassNode()); alpar@103: return id; alpar@103: } else { alpar@103: int id = first_free_class; alpar@103: first_free_class = classes[id].next; alpar@103: return id; alpar@103: } alpar@103: } alpar@103: alpar@103: void deleteClass(int id) { alpar@103: classes[id].next = first_free_class; alpar@103: first_free_class = id; alpar@103: } alpar@103: alpar@103: struct ItemNode { alpar@103: int parent; alpar@103: Item item; alpar@103: Value prio; alpar@103: int next, prev; alpar@103: int left, right; alpar@103: int size; alpar@103: }; alpar@103: alpar@103: int first_free_node; alpar@103: std::vector nodes; alpar@103: alpar@103: int newNode() { alpar@103: if (first_free_node < 0) { alpar@103: int id = nodes.size(); alpar@103: nodes.push_back(ItemNode()); alpar@103: return id; alpar@103: } else { alpar@103: int id = first_free_node; alpar@103: first_free_node = nodes[id].next; alpar@103: return id; alpar@103: } alpar@103: } alpar@103: alpar@103: void deleteNode(int id) { alpar@103: nodes[id].next = first_free_node; alpar@103: first_free_node = id; alpar@103: } alpar@103: alpar@103: Comp comp; alpar@103: alpar@103: int findClass(int id) const { alpar@103: int kd = id; alpar@103: while (kd >= 0) { alpar@103: kd = nodes[kd].parent; alpar@103: } alpar@103: return ~kd; alpar@103: } alpar@103: alpar@103: int leftNode(int id) const { alpar@103: int kd = ~(classes[id].parent); alpar@103: for (int i = 0; i < classes[id].depth; ++i) { alpar@103: kd = nodes[kd].left; alpar@103: } alpar@103: return kd; alpar@103: } alpar@103: alpar@103: int nextNode(int id) const { alpar@103: int depth = 0; alpar@103: while (id >= 0 && nodes[id].next == -1) { alpar@103: id = nodes[id].parent; alpar@103: ++depth; alpar@103: } alpar@103: if (id < 0) { alpar@103: return -1; alpar@103: } alpar@103: id = nodes[id].next; alpar@103: while (depth--) { alpar@209: id = nodes[id].left; alpar@103: } alpar@103: return id; alpar@103: } alpar@103: alpar@103: alpar@103: void setPrio(int id) { alpar@103: int jd = nodes[id].left; alpar@103: nodes[id].prio = nodes[jd].prio; alpar@103: nodes[id].item = nodes[jd].item; alpar@103: jd = nodes[jd].next; alpar@103: while (jd != -1) { alpar@103: if (comp(nodes[jd].prio, nodes[id].prio)) { alpar@103: nodes[id].prio = nodes[jd].prio; alpar@103: nodes[id].item = nodes[jd].item; alpar@103: } alpar@103: jd = nodes[jd].next; alpar@103: } alpar@103: } alpar@103: alpar@103: void push(int id, int jd) { alpar@103: nodes[id].size = 1; alpar@103: nodes[id].left = nodes[id].right = jd; alpar@103: nodes[jd].next = nodes[jd].prev = -1; alpar@103: nodes[jd].parent = id; alpar@103: } alpar@103: alpar@103: void pushAfter(int id, int jd) { alpar@103: int kd = nodes[id].parent; alpar@103: if (nodes[id].next != -1) { alpar@103: nodes[nodes[id].next].prev = jd; alpar@103: if (kd >= 0) { alpar@103: nodes[kd].size += 1; alpar@103: } alpar@103: } else { alpar@103: if (kd >= 0) { alpar@103: nodes[kd].right = jd; alpar@103: nodes[kd].size += 1; alpar@103: } alpar@103: } alpar@103: nodes[jd].next = nodes[id].next; alpar@103: nodes[jd].prev = id; alpar@103: nodes[id].next = jd; alpar@103: nodes[jd].parent = kd; alpar@103: } alpar@103: alpar@103: void pushRight(int id, int jd) { alpar@103: nodes[id].size += 1; alpar@103: nodes[jd].prev = nodes[id].right; alpar@103: nodes[jd].next = -1; alpar@103: nodes[nodes[id].right].next = jd; alpar@103: nodes[id].right = jd; alpar@103: nodes[jd].parent = id; alpar@103: } alpar@103: alpar@103: void popRight(int id) { alpar@103: nodes[id].size -= 1; alpar@103: int jd = nodes[id].right; alpar@103: nodes[nodes[jd].prev].next = -1; alpar@103: nodes[id].right = nodes[jd].prev; alpar@103: } alpar@103: alpar@103: void splice(int id, int jd) { alpar@103: nodes[id].size += nodes[jd].size; alpar@103: nodes[nodes[id].right].next = nodes[jd].left; alpar@103: nodes[nodes[jd].left].prev = nodes[id].right; alpar@103: int kd = nodes[jd].left; alpar@103: while (kd != -1) { alpar@103: nodes[kd].parent = id; alpar@103: kd = nodes[kd].next; alpar@103: } alpar@103: nodes[id].right = nodes[jd].right; alpar@103: } alpar@103: alpar@103: void split(int id, int jd) { alpar@103: int kd = nodes[id].parent; alpar@103: nodes[kd].right = nodes[id].prev; alpar@103: nodes[nodes[id].prev].next = -1; alpar@209: alpar@103: nodes[jd].left = id; alpar@103: nodes[id].prev = -1; alpar@103: int num = 0; alpar@103: while (id != -1) { alpar@103: nodes[id].parent = jd; alpar@103: nodes[jd].right = id; alpar@103: id = nodes[id].next; alpar@103: ++num; alpar@209: } alpar@103: nodes[kd].size -= num; alpar@103: nodes[jd].size = num; alpar@103: } alpar@103: alpar@103: void pushLeft(int id, int jd) { alpar@103: nodes[id].size += 1; alpar@103: nodes[jd].next = nodes[id].left; alpar@103: nodes[jd].prev = -1; alpar@103: nodes[nodes[id].left].prev = jd; alpar@103: nodes[id].left = jd; alpar@103: nodes[jd].parent = id; alpar@103: } alpar@103: alpar@103: void popLeft(int id) { alpar@103: nodes[id].size -= 1; alpar@103: int jd = nodes[id].left; alpar@103: nodes[nodes[jd].next].prev = -1; alpar@103: nodes[id].left = nodes[jd].next; alpar@103: } alpar@103: alpar@103: void repairLeft(int id) { alpar@103: int jd = ~(classes[id].parent); alpar@103: while (nodes[jd].left != -1) { alpar@209: int kd = nodes[jd].left; alpar@209: if (nodes[jd].size == 1) { alpar@209: if (nodes[jd].parent < 0) { alpar@209: classes[id].parent = ~kd; alpar@209: classes[id].depth -= 1; alpar@209: nodes[kd].parent = ~id; alpar@209: deleteNode(jd); alpar@209: jd = kd; alpar@209: } else { alpar@209: int pd = nodes[jd].parent; alpar@209: if (nodes[nodes[jd].next].size < cmax) { alpar@209: pushLeft(nodes[jd].next, nodes[jd].left); alpar@209: if (less(nodes[jd].left, nodes[jd].next)) { alpar@209: nodes[nodes[jd].next].prio = nodes[nodes[jd].left].prio; alpar@209: nodes[nodes[jd].next].item = nodes[nodes[jd].left].item; alpar@209: } alpar@209: popLeft(pd); alpar@209: deleteNode(jd); alpar@209: jd = pd; alpar@209: } else { alpar@209: int ld = nodes[nodes[jd].next].left; alpar@209: popLeft(nodes[jd].next); alpar@209: pushRight(jd, ld); alpar@209: if (less(ld, nodes[jd].left)) { alpar@209: nodes[jd].item = nodes[ld].item; alpar@209: nodes[jd].prio = nodes[jd].prio; alpar@209: } alpar@209: if (nodes[nodes[jd].next].item == nodes[ld].item) { alpar@209: setPrio(nodes[jd].next); alpar@209: } alpar@209: jd = nodes[jd].left; alpar@209: } alpar@209: } alpar@209: } else { alpar@209: jd = nodes[jd].left; alpar@209: } alpar@103: } alpar@209: } alpar@103: alpar@103: void repairRight(int id) { alpar@103: int jd = ~(classes[id].parent); alpar@103: while (nodes[jd].right != -1) { alpar@209: int kd = nodes[jd].right; alpar@209: if (nodes[jd].size == 1) { alpar@209: if (nodes[jd].parent < 0) { alpar@209: classes[id].parent = ~kd; alpar@209: classes[id].depth -= 1; alpar@209: nodes[kd].parent = ~id; alpar@209: deleteNode(jd); alpar@209: jd = kd; alpar@209: } else { alpar@209: int pd = nodes[jd].parent; alpar@209: if (nodes[nodes[jd].prev].size < cmax) { alpar@209: pushRight(nodes[jd].prev, nodes[jd].right); alpar@209: if (less(nodes[jd].right, nodes[jd].prev)) { alpar@209: nodes[nodes[jd].prev].prio = nodes[nodes[jd].right].prio; alpar@209: nodes[nodes[jd].prev].item = nodes[nodes[jd].right].item; alpar@209: } alpar@209: popRight(pd); alpar@209: deleteNode(jd); alpar@209: jd = pd; alpar@209: } else { alpar@209: int ld = nodes[nodes[jd].prev].right; alpar@209: popRight(nodes[jd].prev); alpar@209: pushLeft(jd, ld); alpar@209: if (less(ld, nodes[jd].right)) { alpar@209: nodes[jd].item = nodes[ld].item; alpar@209: nodes[jd].prio = nodes[jd].prio; alpar@209: } alpar@209: if (nodes[nodes[jd].prev].item == nodes[ld].item) { alpar@209: setPrio(nodes[jd].prev); alpar@209: } alpar@209: jd = nodes[jd].right; alpar@209: } alpar@209: } alpar@209: } else { alpar@209: jd = nodes[jd].right; alpar@209: } alpar@103: } alpar@103: } alpar@103: alpar@103: alpar@103: bool less(int id, int jd) const { alpar@103: return comp(nodes[id].prio, nodes[jd].prio); alpar@103: } alpar@103: alpar@103: bool equal(int id, int jd) const { alpar@103: return !less(id, jd) && !less(jd, id); alpar@103: } alpar@103: alpar@103: alpar@103: public: alpar@103: alpar@103: /// \brief Returns true when the given class is alive. alpar@103: /// alpar@103: /// Returns true when the given class is alive, ie. the class is alpar@103: /// not nested into other class. alpar@103: bool alive(int cls) const { alpar@103: return classes[cls].parent < 0; alpar@103: } alpar@103: alpar@103: /// \brief Returns true when the given class is trivial. alpar@103: /// alpar@103: /// Returns true when the given class is trivial, ie. the class alpar@103: /// contains just one item directly. alpar@103: bool trivial(int cls) const { alpar@103: return classes[cls].left == -1; alpar@103: } alpar@103: alpar@103: /// \brief Constructs the union-find. alpar@103: /// alpar@209: /// Constructs the union-find. alpar@103: /// \brief _index The index map of the union-find. The data alpar@103: /// structure uses internally for store references. alpar@209: HeapUnionFind(ItemIntMap& _index) alpar@209: : index(_index), first_class(-1), alpar@209: first_free_class(-1), first_free_node(-1) {} alpar@103: alpar@103: /// \brief Insert a new node into a new component. alpar@103: /// alpar@103: /// Insert a new node into a new component. alpar@103: /// \param item The item of the new node. alpar@103: /// \param prio The priority of the new node. alpar@103: /// \return The class id of the one-item-heap. alpar@103: int insert(const Item& item, const Value& prio) { alpar@103: int id = newNode(); alpar@103: nodes[id].item = item; alpar@103: nodes[id].prio = prio; alpar@103: nodes[id].size = 0; alpar@103: alpar@103: nodes[id].prev = -1; alpar@103: nodes[id].next = -1; alpar@103: alpar@103: nodes[id].left = -1; alpar@103: nodes[id].right = -1; alpar@103: alpar@103: nodes[id].item = item; alpar@103: index[item] = id; alpar@209: alpar@103: int class_id = newClass(); alpar@103: classes[class_id].parent = ~id; alpar@103: classes[class_id].depth = 0; alpar@103: alpar@103: classes[class_id].left = -1; alpar@103: classes[class_id].right = -1; alpar@209: alpar@103: if (first_class != -1) { alpar@103: classes[first_class].prev = class_id; alpar@103: } alpar@103: classes[class_id].next = first_class; alpar@103: classes[class_id].prev = -1; alpar@103: first_class = class_id; alpar@103: alpar@103: nodes[id].parent = ~class_id; alpar@209: alpar@103: return class_id; alpar@103: } alpar@103: alpar@103: /// \brief The class of the item. alpar@103: /// alpar@103: /// \return The alive class id of the item, which is not nested into alpar@103: /// other classes. alpar@103: /// alpar@103: /// The time complexity is O(log(n)). alpar@103: int find(const Item& item) const { alpar@103: return findClass(index[item]); alpar@103: } alpar@209: alpar@103: /// \brief Joins the classes. alpar@103: /// alpar@103: /// The current function joins the given classes. The parameter is alpar@103: /// an STL range which should be contains valid class ids. The alpar@103: /// time complexity is O(log(n)*k) where n is the overall number alpar@103: /// of the joined nodes and k is the number of classes. alpar@103: /// \return The class of the joined classes. alpar@103: /// \pre The range should contain at least two class ids. alpar@103: template alpar@103: int join(Iterator begin, Iterator end) { alpar@103: std::vector cs; alpar@103: for (Iterator it = begin; it != end; ++it) { alpar@103: cs.push_back(*it); alpar@103: } alpar@103: alpar@103: int class_id = newClass(); alpar@103: { // creation union-find alpar@103: alpar@103: if (first_class != -1) { alpar@103: classes[first_class].prev = class_id; alpar@103: } alpar@103: classes[class_id].next = first_class; alpar@103: classes[class_id].prev = -1; alpar@103: first_class = class_id; alpar@103: alpar@103: classes[class_id].depth = classes[cs[0]].depth; alpar@103: classes[class_id].parent = classes[cs[0]].parent; alpar@103: nodes[~(classes[class_id].parent)].parent = ~class_id; alpar@103: alpar@103: int l = cs[0]; alpar@103: alpar@103: classes[class_id].left = l; alpar@103: classes[class_id].right = l; alpar@103: alpar@103: if (classes[l].next != -1) { alpar@103: classes[classes[l].next].prev = classes[l].prev; alpar@103: } alpar@103: classes[classes[l].prev].next = classes[l].next; alpar@209: alpar@103: classes[l].prev = -1; alpar@103: classes[l].next = -1; alpar@103: alpar@103: classes[l].depth = leftNode(l); alpar@103: classes[l].parent = class_id; alpar@209: alpar@103: } alpar@103: alpar@103: { // merging of heap alpar@103: int l = class_id; alpar@103: for (int ci = 1; ci < int(cs.size()); ++ci) { alpar@103: int r = cs[ci]; alpar@103: int rln = leftNode(r); alpar@103: if (classes[l].depth > classes[r].depth) { alpar@103: int id = ~(classes[l].parent); alpar@103: for (int i = classes[r].depth + 1; i < classes[l].depth; ++i) { alpar@103: id = nodes[id].right; alpar@103: } alpar@103: while (id >= 0 && nodes[id].size == cmax) { alpar@103: int new_id = newNode(); alpar@103: int right_id = nodes[id].right; alpar@103: alpar@103: popRight(id); alpar@103: if (nodes[id].item == nodes[right_id].item) { alpar@103: setPrio(id); alpar@103: } alpar@103: push(new_id, right_id); alpar@103: pushRight(new_id, ~(classes[r].parent)); alpar@103: setPrio(new_id); alpar@103: alpar@103: id = nodes[id].parent; alpar@103: classes[r].parent = ~new_id; alpar@103: } alpar@103: if (id < 0) { alpar@103: int new_parent = newNode(); alpar@103: nodes[new_parent].next = -1; alpar@103: nodes[new_parent].prev = -1; alpar@103: nodes[new_parent].parent = ~l; alpar@103: alpar@103: push(new_parent, ~(classes[l].parent)); alpar@103: pushRight(new_parent, ~(classes[r].parent)); alpar@103: setPrio(new_parent); alpar@103: alpar@103: classes[l].parent = ~new_parent; alpar@103: classes[l].depth += 1; alpar@103: } else { alpar@103: pushRight(id, ~(classes[r].parent)); alpar@103: while (id >= 0 && less(~(classes[r].parent), id)) { alpar@103: nodes[id].prio = nodes[~(classes[r].parent)].prio; alpar@103: nodes[id].item = nodes[~(classes[r].parent)].item; alpar@103: id = nodes[id].parent; alpar@103: } alpar@103: } alpar@103: } else if (classes[r].depth > classes[l].depth) { alpar@103: int id = ~(classes[r].parent); alpar@103: for (int i = classes[l].depth + 1; i < classes[r].depth; ++i) { alpar@103: id = nodes[id].left; alpar@103: } alpar@103: while (id >= 0 && nodes[id].size == cmax) { alpar@103: int new_id = newNode(); alpar@103: int left_id = nodes[id].left; alpar@103: alpar@103: popLeft(id); alpar@103: if (nodes[id].prio == nodes[left_id].prio) { alpar@103: setPrio(id); alpar@103: } alpar@103: push(new_id, left_id); alpar@103: pushLeft(new_id, ~(classes[l].parent)); alpar@103: setPrio(new_id); alpar@103: alpar@103: id = nodes[id].parent; alpar@103: classes[l].parent = ~new_id; alpar@103: alpar@103: } alpar@103: if (id < 0) { alpar@103: int new_parent = newNode(); alpar@103: nodes[new_parent].next = -1; alpar@103: nodes[new_parent].prev = -1; alpar@103: nodes[new_parent].parent = ~l; alpar@103: alpar@103: push(new_parent, ~(classes[r].parent)); alpar@103: pushLeft(new_parent, ~(classes[l].parent)); alpar@103: setPrio(new_parent); alpar@209: alpar@103: classes[r].parent = ~new_parent; alpar@103: classes[r].depth += 1; alpar@103: } else { alpar@103: pushLeft(id, ~(classes[l].parent)); alpar@103: while (id >= 0 && less(~(classes[l].parent), id)) { alpar@103: nodes[id].prio = nodes[~(classes[l].parent)].prio; alpar@103: nodes[id].item = nodes[~(classes[l].parent)].item; alpar@103: id = nodes[id].parent; alpar@103: } alpar@103: } alpar@103: nodes[~(classes[r].parent)].parent = ~l; alpar@103: classes[l].parent = classes[r].parent; alpar@103: classes[l].depth = classes[r].depth; alpar@103: } else { alpar@209: if (classes[l].depth != 0 && alpar@209: nodes[~(classes[l].parent)].size + alpar@103: nodes[~(classes[r].parent)].size <= cmax) { alpar@103: splice(~(classes[l].parent), ~(classes[r].parent)); alpar@103: deleteNode(~(classes[r].parent)); alpar@103: if (less(~(classes[r].parent), ~(classes[l].parent))) { alpar@209: nodes[~(classes[l].parent)].prio = alpar@103: nodes[~(classes[r].parent)].prio; alpar@209: nodes[~(classes[l].parent)].item = alpar@103: nodes[~(classes[r].parent)].item; alpar@103: } alpar@103: } else { alpar@103: int new_parent = newNode(); alpar@103: nodes[new_parent].next = nodes[new_parent].prev = -1; alpar@103: push(new_parent, ~(classes[l].parent)); alpar@103: pushRight(new_parent, ~(classes[r].parent)); alpar@103: setPrio(new_parent); alpar@209: alpar@103: classes[l].parent = ~new_parent; alpar@103: classes[l].depth += 1; alpar@103: nodes[new_parent].parent = ~l; alpar@103: } alpar@103: } alpar@103: if (classes[r].next != -1) { alpar@103: classes[classes[r].next].prev = classes[r].prev; alpar@103: } alpar@103: classes[classes[r].prev].next = classes[r].next; alpar@103: alpar@103: classes[r].prev = classes[l].right; alpar@103: classes[classes[l].right].next = r; alpar@103: classes[l].right = r; alpar@103: classes[r].parent = l; alpar@103: alpar@103: classes[r].next = -1; alpar@103: classes[r].depth = rln; alpar@103: } alpar@103: } alpar@103: return class_id; alpar@103: } alpar@103: alpar@103: /// \brief Split the class to subclasses. alpar@103: /// alpar@103: /// The current function splits the given class. The join, which alpar@103: /// made the current class, stored a reference to the alpar@103: /// subclasses. The \c splitClass() member restores the classes alpar@103: /// and creates the heaps. The parameter is an STL output iterator alpar@103: /// which will be filled with the subclass ids. The time alpar@103: /// complexity is O(log(n)*k) where n is the overall number of alpar@103: /// nodes in the splitted classes and k is the number of the alpar@103: /// classes. alpar@103: template alpar@103: void split(int cls, Iterator out) { alpar@103: std::vector cs; alpar@103: { // splitting union-find alpar@103: int id = cls; alpar@103: int l = classes[id].left; alpar@103: alpar@103: classes[l].parent = classes[id].parent; alpar@103: classes[l].depth = classes[id].depth; alpar@103: alpar@103: nodes[~(classes[l].parent)].parent = ~l; alpar@103: alpar@103: *out++ = l; alpar@103: alpar@103: while (l != -1) { alpar@103: cs.push_back(l); alpar@103: l = classes[l].next; alpar@103: } alpar@103: alpar@103: classes[classes[id].right].next = first_class; alpar@103: classes[first_class].prev = classes[id].right; alpar@103: first_class = classes[id].left; alpar@209: alpar@103: if (classes[id].next != -1) { alpar@103: classes[classes[id].next].prev = classes[id].prev; alpar@103: } alpar@103: classes[classes[id].prev].next = classes[id].next; alpar@209: alpar@103: deleteClass(id); alpar@103: } alpar@103: alpar@103: { alpar@103: for (int i = 1; i < int(cs.size()); ++i) { alpar@103: int l = classes[cs[i]].depth; alpar@103: while (nodes[nodes[l].parent].left == l) { alpar@103: l = nodes[l].parent; alpar@103: } alpar@209: int r = l; alpar@103: while (nodes[l].parent >= 0) { alpar@103: l = nodes[l].parent; alpar@103: int new_node = newNode(); alpar@103: alpar@103: nodes[new_node].prev = -1; alpar@103: nodes[new_node].next = -1; alpar@103: alpar@103: split(r, new_node); alpar@103: pushAfter(l, new_node); alpar@103: setPrio(l); alpar@103: setPrio(new_node); alpar@103: r = new_node; alpar@103: } alpar@103: classes[cs[i]].parent = ~r; alpar@103: classes[cs[i]].depth = classes[~(nodes[l].parent)].depth; alpar@103: nodes[r].parent = ~cs[i]; alpar@103: alpar@103: nodes[l].next = -1; alpar@103: nodes[r].prev = -1; alpar@103: alpar@103: repairRight(~(nodes[l].parent)); alpar@103: repairLeft(cs[i]); alpar@209: alpar@103: *out++ = cs[i]; alpar@103: } alpar@103: } alpar@103: } alpar@103: alpar@103: /// \brief Gives back the priority of the current item. alpar@103: /// alpar@103: /// \return Gives back the priority of the current item. alpar@103: const Value& operator[](const Item& item) const { alpar@103: return nodes[index[item]].prio; alpar@103: } alpar@103: alpar@103: /// \brief Sets the priority of the current item. alpar@103: /// alpar@103: /// Sets the priority of the current item. alpar@103: void set(const Item& item, const Value& prio) { alpar@103: if (comp(prio, nodes[index[item]].prio)) { alpar@103: decrease(item, prio); alpar@103: } else if (!comp(prio, nodes[index[item]].prio)) { alpar@103: increase(item, prio); alpar@103: } alpar@103: } alpar@209: alpar@103: /// \brief Increase the priority of the current item. alpar@103: /// alpar@103: /// Increase the priority of the current item. alpar@103: void increase(const Item& item, const Value& prio) { alpar@103: int id = index[item]; alpar@103: int kd = nodes[id].parent; alpar@103: nodes[id].prio = prio; alpar@103: while (kd >= 0 && nodes[kd].item == item) { alpar@103: setPrio(kd); alpar@103: kd = nodes[kd].parent; alpar@103: } alpar@103: } alpar@103: alpar@103: /// \brief Increase the priority of the current item. alpar@103: /// alpar@103: /// Increase the priority of the current item. alpar@103: void decrease(const Item& item, const Value& prio) { alpar@103: int id = index[item]; alpar@103: int kd = nodes[id].parent; alpar@103: nodes[id].prio = prio; alpar@103: while (kd >= 0 && less(id, kd)) { alpar@103: nodes[kd].prio = prio; alpar@103: nodes[kd].item = item; alpar@103: kd = nodes[kd].parent; alpar@103: } alpar@103: } alpar@209: alpar@103: /// \brief Gives back the minimum priority of the class. alpar@103: /// alpar@103: /// \return Gives back the minimum priority of the class. alpar@103: const Value& classPrio(int cls) const { alpar@103: return nodes[~(classes[cls].parent)].prio; alpar@103: } alpar@103: alpar@103: /// \brief Gives back the minimum priority item of the class. alpar@103: /// alpar@103: /// \return Gives back the minimum priority item of the class. alpar@103: const Item& classTop(int cls) const { alpar@103: return nodes[~(classes[cls].parent)].item; alpar@103: } alpar@103: alpar@103: /// \brief Gives back a representant item of the class. alpar@209: /// alpar@103: /// The representant is indpendent from the priorities of the alpar@209: /// items. alpar@103: /// \return Gives back a representant item of the class. alpar@103: const Item& classRep(int id) const { alpar@103: int parent = classes[id].parent; alpar@103: return nodes[parent >= 0 ? classes[id].depth : leftNode(id)].item; alpar@103: } alpar@103: ladanyi@236: /// \brief LEMON style iterator for the items of a class. alpar@103: /// alpar@103: /// ClassIt is a lemon style iterator for the components. It iterates alpar@103: /// on the items of a class. By example if you want to iterate on alpar@103: /// each items of each classes then you may write the next code. alpar@103: ///\code alpar@103: /// for (ClassIt cit(huf); cit != INVALID; ++cit) { alpar@103: /// std::cout << "Class: "; alpar@103: /// for (ItemIt iit(huf, cit); iit != INVALID; ++iit) { alpar@103: /// std::cout << toString(iit) << ' ' << std::endl; alpar@103: /// } alpar@103: /// std::cout << std::endl; alpar@103: /// } alpar@103: ///\endcode alpar@103: class ItemIt { alpar@103: private: alpar@103: alpar@103: const HeapUnionFind* _huf; alpar@103: int _id, _lid; alpar@209: alpar@103: public: alpar@103: alpar@209: /// \brief Default constructor alpar@103: /// alpar@209: /// Default constructor alpar@103: ItemIt() {} alpar@103: alpar@103: ItemIt(const HeapUnionFind& huf, int cls) : _huf(&huf) { alpar@103: int id = cls; alpar@103: int parent = _huf->classes[id].parent; alpar@103: if (parent >= 0) { alpar@103: _id = _huf->classes[id].depth; alpar@103: if (_huf->classes[id].next != -1) { alpar@103: _lid = _huf->classes[_huf->classes[id].next].depth; alpar@103: } else { alpar@103: _lid = -1; alpar@103: } alpar@103: } else { alpar@103: _id = _huf->leftNode(id); alpar@103: _lid = -1; alpar@209: } alpar@103: } alpar@209: alpar@103: /// \brief Increment operator alpar@103: /// alpar@103: /// It steps to the next item in the class. alpar@103: ItemIt& operator++() { alpar@103: _id = _huf->nextNode(_id); alpar@103: return *this; alpar@103: } alpar@103: alpar@103: /// \brief Conversion operator alpar@103: /// alpar@103: /// It converts the iterator to the current item. alpar@103: operator const Item&() const { alpar@103: return _huf->nodes[_id].item; alpar@103: } alpar@209: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ItemIt& i) { alpar@103: return i._id == _id; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ItemIt& i) { alpar@103: return i._id != _id; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(Invalid) { alpar@103: return _id == _lid; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(Invalid) { alpar@103: return _id != _lid; alpar@103: } alpar@209: alpar@103: }; alpar@103: alpar@103: /// \brief Class iterator alpar@103: /// alpar@209: /// The iterator stores alpar@103: class ClassIt { alpar@103: private: alpar@103: alpar@103: const HeapUnionFind* _huf; alpar@103: int _id; alpar@103: alpar@103: public: alpar@103: alpar@209: ClassIt(const HeapUnionFind& huf) alpar@103: : _huf(&huf), _id(huf.first_class) {} alpar@103: alpar@209: ClassIt(const HeapUnionFind& huf, int cls) alpar@103: : _huf(&huf), _id(huf.classes[cls].left) {} alpar@103: alpar@103: ClassIt(Invalid) : _huf(0), _id(-1) {} alpar@209: alpar@103: const ClassIt& operator++() { alpar@103: _id = _huf->classes[_id].next; alpar@209: return *this; alpar@103: } alpar@103: alpar@103: /// \brief Equality operator alpar@103: /// alpar@103: /// Equality operator alpar@209: bool operator==(const ClassIt& i) { alpar@103: return i._id == _id; alpar@103: } alpar@103: alpar@103: /// \brief Inequality operator alpar@103: /// alpar@103: /// Inequality operator alpar@209: bool operator!=(const ClassIt& i) { alpar@103: return i._id != _id; alpar@209: } alpar@209: alpar@103: operator int() const { alpar@209: return _id; alpar@103: } alpar@209: alpar@103: }; alpar@103: alpar@103: }; alpar@103: alpar@103: //! @} alpar@103: alpar@103: } //namespace lemon alpar@103: alpar@103: #endif //LEMON_UNION_FIND_H