lemon/unionfind.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2006 00d59f733817
child 2308 cddae1c4fee6
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

The tests have been modified to the current implementation
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_UNION_FIND_H
    20 #define LEMON_UNION_FIND_H
    21 
    22 //!\ingroup auxdat
    23 //!\file
    24 //!\brief Union-Find data structures.
    25 //!
    26 
    27 #include <vector>
    28 #include <list>
    29 #include <utility>
    30 #include <algorithm>
    31 
    32 #include <lemon/bits/invalid.h>
    33 
    34 namespace lemon {
    35 
    36   //! \addtogroup auxdat
    37   //! @{
    38 
    39   /// \brief A \e Union-Find data structure implementation
    40   ///
    41   /// The class implements the \e Union-Find data structure. 
    42   /// The union operation uses rank heuristic, while
    43   /// the find operation uses path compression.
    44   /// This is a very simple but efficient implementation, providing 
    45   /// only four methods: join (union), find, insert and size.
    46   /// For more features see the \ref UnionFindEnum class.
    47   ///
    48   /// It is primarily used in Kruskal algorithm for finding minimal
    49   /// cost spanning tree in a graph.
    50   /// \sa kruskal()
    51   ///
    52   /// \pre You need to add all the elements by the \ref insert()
    53   /// method.  
    54   template <typename Item, typename ItemIntMap>
    55   class UnionFind {
    56     
    57   public:
    58     typedef Item ElementType;
    59 
    60   private:
    61     // If the items vector stores negative value for an item then
    62     // that item is root item and it has -items[it] component size.
    63     // Else the items[it] contains the index of the parent.
    64     std::vector<int> items;
    65     ItemIntMap& index;
    66 
    67     bool rep(int idx) const {
    68       return items[idx] < 0;
    69     }
    70 
    71     int repIndex(int idx) const {
    72       int k = idx;
    73       while (!rep(k)) {
    74         k = items[k] ;
    75       }
    76       while (idx != k) {
    77         int next = items[idx];
    78         const_cast<int&>(items[idx]) = k;
    79         idx = next;
    80       }
    81       return k;
    82     }
    83 
    84   public:
    85 
    86     /// \brief Constructor
    87     ///
    88     /// Constructor of the UnionFind class. You should give an item to
    89     /// integer map which will be used from the data structure. If you
    90     /// modify directly this map that may cause segmentation fault,
    91     /// invalid data structure, or infinite loop when you use again
    92     /// the union-find.
    93     UnionFind(ItemIntMap& m) : index(m) {}
    94 
    95     /// \brief Returns the index of the element's component.
    96     ///
    97     /// The method returns the index of the element's component.
    98     /// This is an integer between zero and the number of inserted elements.
    99     ///
   100     int find(const Item& a) {
   101       return repIndex(index[a]);
   102     }
   103 
   104     /// \brief Inserts a new element into the structure.
   105     ///
   106     /// This method inserts a new element into the data structure. 
   107     ///
   108     /// The method returns the index of the new component.
   109     int insert(const Item& a) {
   110       int n = items.size();
   111       items.push_back(-1);
   112       index.set(a,n);
   113       return n;
   114     }
   115 
   116     /// \brief Joining the components of element \e a and element \e b.
   117     ///
   118     /// This is the \e union operation of the Union-Find structure. 
   119     /// Joins the component of element \e a and component of
   120     /// element \e b. If \e a and \e b are in the same component then
   121     /// it returns false otherwise it returns true.
   122     bool join(const Item& a, const Item& b) {
   123       int ka = repIndex(index[a]);
   124       int kb = repIndex(index[b]);
   125 
   126       if ( ka == kb ) 
   127 	return false;
   128 
   129       if (items[ka] < items[kb]) {
   130 	items[ka] += items[kb];
   131 	items[kb] = ka;
   132       } else {
   133 	items[kb] += items[ka];
   134 	items[ka] = kb;
   135       }
   136       return true;
   137     }
   138 
   139     /// \brief Returns the size of the component of element \e a.
   140     ///
   141     /// Returns the size of the component of element \e a.
   142     int size(const Item& a) {
   143       int k = repIndex(index[a]);
   144       return - items[k];
   145     }
   146 
   147   };
   148 
   149 
   150   /// \brief A \e Union-Find data structure implementation which
   151   /// is able to enumerate the components.
   152   ///
   153   /// The class implements a \e Union-Find data structure
   154   /// which is able to enumerate the components and the items in
   155   /// a component. If you don't need this feature then perhaps it's
   156   /// better to use the \ref UnionFind class which is more efficient.
   157   ///
   158   /// The union operation uses rank heuristic, while
   159   /// the find operation uses path compression.
   160   ///
   161   /// \pre You need to add all the elements by the \ref insert()
   162   /// method.
   163   ///
   164   template <typename _Item, typename _ItemIntMap>
   165   class UnionFindEnum {
   166   public:
   167     
   168     typedef _Item Item;
   169     typedef _ItemIntMap ItemIntMap;
   170     
   171   private:
   172     
   173     // If the parent stores negative value for an item then that item
   174     // is root item and it has -items[it].parent component size.  Else
   175     // the items[it].parent contains the index of the parent.
   176     //
   177     // The \c nextItem and \c prevItem provides the double-linked
   178     // cyclic list of one component's items. The \c prevClass and
   179     // \c nextClass gives the double linked list of the representant
   180     // items. 
   181     struct ItemT {
   182       int parent;
   183       Item item;
   184 
   185       int nextItem, prevItem;
   186       int nextClass, prevClass;
   187     };
   188 
   189     std::vector<ItemT> items;
   190     ItemIntMap& index;
   191 
   192     int firstClass;
   193 
   194 
   195     bool rep(int idx) const {
   196       return items[idx].parent < 0;
   197     }
   198 
   199     int repIndex(int idx) const {
   200       int k = idx;
   201       while (!rep(k)) {
   202         k = items[k].parent;
   203       }
   204       while (idx != k) {
   205         int next = items[idx].parent;
   206         const_cast<int&>(items[idx].parent) = k;
   207         idx = next;
   208       }
   209       return k;
   210     }
   211 
   212     void unlaceClass(int k) {
   213       if (items[k].prevClass != -1) {
   214         items[items[k].prevClass].nextClass = items[k].nextClass;
   215       } else {
   216         firstClass = items[k].nextClass;
   217       }
   218       if (items[k].nextClass != -1) {
   219         items[items[k].nextClass].prevClass = items[k].prevClass;
   220       }
   221     } 
   222 
   223     void spliceItems(int ak, int bk) {
   224       items[items[ak].prevItem].nextItem = bk;
   225       items[items[bk].prevItem].nextItem = ak;
   226       int tmp = items[ak].prevItem;
   227       items[ak].prevItem = items[bk].prevItem;
   228       items[bk].prevItem = tmp;
   229         
   230     }
   231 
   232   public:
   233 
   234     UnionFindEnum(ItemIntMap& _index) 
   235       : items(), index(_index), firstClass(-1) {}
   236     
   237     /// \brief Inserts the given element into a new component.
   238     ///
   239     /// This method creates a new component consisting only of the
   240     /// given element.
   241     ///
   242     void insert(const Item& item) {
   243       ItemT t;
   244 
   245       int idx = items.size();
   246       index.set(item, idx);
   247 
   248       t.nextItem = idx;
   249       t.prevItem = idx;
   250       t.item = item;
   251       t.parent = -1;
   252       
   253       t.nextClass = firstClass;
   254       if (firstClass != -1) {
   255         items[firstClass].prevClass = idx;
   256       }
   257       t.prevClass = -1;
   258       firstClass = idx;
   259 
   260       items.push_back(t);
   261     }
   262 
   263     /// \brief Inserts the given element into the component of the others.
   264     ///
   265     /// This methods inserts the element \e a into the component of the
   266     /// element \e comp. 
   267     void insert(const Item& item, const Item& comp) {
   268       int k = repIndex(index[comp]);
   269       ItemT t;
   270 
   271       int idx = items.size();
   272       index.set(item, idx);
   273 
   274       t.prevItem = k;
   275       t.nextItem = items[k].nextItem;
   276       items[items[k].nextItem].prevItem = idx;
   277       items[k].nextItem = idx;
   278 
   279       t.item = item;
   280       t.parent = k;
   281 
   282       --items[k].parent;
   283 
   284       items.push_back(t);
   285     }
   286 
   287     /// \brief Finds the leader of the component of the given element.
   288     ///
   289     /// The method returns the leader of the component of the given element.
   290     const Item& find(const Item &item) const {
   291       return items[repIndex(index[item])].item;
   292     }
   293 
   294     /// \brief Joining the component of element \e a and element \e b.
   295     ///
   296     /// This is the \e union operation of the Union-Find structure. 
   297     /// Joins the component of element \e a and component of
   298     /// element \e b. If \e a and \e b are in the same component then
   299     /// returns false else returns true.
   300     bool join(const Item& a, const Item& b) {
   301 
   302       int ak = repIndex(index[a]);
   303       int bk = repIndex(index[b]);
   304 
   305       if (ak == bk) {
   306 	return false;
   307       }
   308 
   309       if ( items[ak].parent < items[bk].parent ) {
   310         unlaceClass(bk);
   311         items[ak].parent += items[bk].parent;
   312 	items[bk].parent = ak;
   313       } else {
   314         unlaceClass(bk);
   315         items[bk].parent += items[ak].parent;
   316 	items[ak].parent = bk;
   317       }
   318       spliceItems(ak, bk);
   319 
   320       return true;
   321     }
   322 
   323     /// \brief Returns the size of the component of element \e a.
   324     ///
   325     /// Returns the size of the component of element \e a.
   326     int size(const Item &item) const {
   327       return - items[repIndex(index[item])].parent;
   328     }
   329 
   330     /// \brief Splits up the component of the element. 
   331     ///
   332     /// Splitting the component of the element into sigleton
   333     /// components (component of size one).
   334     void split(const Item &item) {
   335       int k = repIndex(index[item]);
   336       int idx = items[k].nextItem;
   337       while (idx != k) {
   338         int next = items[idx].nextItem;
   339         
   340         items[idx].parent = -1;
   341         items[idx].prevItem = idx;
   342         items[idx].nextItem = idx;
   343         
   344         items[idx].nextClass = firstClass;
   345         items[firstClass].prevClass = idx;
   346         firstClass = idx;
   347 
   348         idx = next;
   349       }
   350 
   351       items[idx].parent = -1;
   352       items[idx].prevItem = idx;
   353       items[idx].nextItem = idx;
   354       
   355       items[firstClass].prevClass = -1;
   356     }
   357 
   358     /// \brief Sets the given element to the leader element of its component.
   359     ///
   360     /// Sets the given element to the leader element of its component.
   361     void makeRep(const Item &item) {
   362       int nk = index[item];
   363       int k = repIndex(nk);
   364       if (nk == k) return;
   365       
   366       if (items[k].prevClass != -1) {
   367         items[items[k].prevClass].nextClass = nk;
   368       } else {
   369         firstClass = nk;
   370       }
   371       if (items[k].nextClass != -1) {
   372         items[items[k].nextClass].prevClass = nk;
   373       }
   374       
   375       int idx = items[k].nextItem;
   376       while (idx != k) {
   377         items[idx].parent = nk;
   378         idx = items[idx].nextItem;
   379       }
   380       
   381       items[nk].parent = items[k].parent;
   382       items[k].parent = nk;
   383     }
   384 
   385     /// \brief Removes the given element from the structure.
   386     ///
   387     /// Removes the element from its component and if the component becomes
   388     /// empty then removes that component from the component list.
   389     ///
   390     /// \warning It is an error to remove an element which is not in
   391     /// the structure.
   392     void erase(const Item &item) {
   393       int idx = index[item];
   394       if (rep(idx)) {
   395         int k = idx;
   396         if (items[k].parent == -1) {
   397           unlaceClass(idx);
   398           return;
   399         } else {
   400           int nk = items[k].nextItem;
   401           if (items[k].prevClass != -1) {
   402             items[items[k].prevClass].nextClass = nk;
   403           } else {
   404             firstClass = nk;
   405           }
   406           if (items[k].nextClass != -1) {
   407             items[items[k].nextClass].prevClass = nk;
   408           }
   409       
   410           int idx = items[k].nextItem;
   411           while (idx != k) {
   412             items[idx].parent = nk;
   413             idx = items[idx].nextItem;
   414           }
   415           
   416           items[nk].parent = items[k].parent + 1;
   417         }
   418       } else {
   419         
   420         int k = repIndex(idx);
   421         idx = items[k].nextItem;
   422         while (idx != k) {
   423           items[idx].parent = k;
   424           idx = items[idx].nextItem;
   425         }
   426 
   427         ++items[k].parent;
   428       }
   429 
   430       idx = index[item];      
   431       items[items[idx].prevItem].nextItem = items[idx].nextItem;
   432       items[items[idx].nextItem].prevItem = items[idx].prevItem;
   433 
   434     }    
   435 
   436     /// \brief Moves the given element to another component.
   437     ///
   438     /// This method moves the element \e a from its component
   439     /// to the component of \e comp.
   440     /// If \e a and \e comp are in the same component then
   441     /// it returns false otherwise it returns true.
   442     bool move(const Item &item, const Item &comp) {
   443       if (repIndex(index[item]) == repIndex(index[comp])) return false;
   444       erase(item);
   445       insert(item, comp);
   446       return true;
   447     }
   448 
   449 
   450     /// \brief Removes the component of the given element from the structure.
   451     ///
   452     /// Removes the component of the given element from the structure.
   453     ///
   454     /// \warning It is an error to give an element which is not in the
   455     /// structure.
   456     void eraseClass(const Item &item) {
   457       unlaceClass(repIndex(index[item]));
   458     }
   459 
   460     /// \brief Lemon style iterator for the representant items.
   461     ///
   462     /// ClassIt is a lemon style iterator for the components. It iterates
   463     /// on the representant items of the classes.
   464     class ClassIt {
   465     public:
   466       /// \brief Constructor of the iterator
   467       ///
   468       /// Constructor of the iterator
   469       ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) {
   470         idx = unionFind->firstClass;
   471       }
   472 
   473       /// \brief Constructor to get invalid iterator
   474       ///
   475       /// Constructor to get invalid iterator
   476       ClassIt(Invalid) : unionFind(0), idx(-1) {}
   477       
   478       /// \brief Increment operator
   479       ///
   480       /// It steps to the next representant item.
   481       ClassIt& operator++() {
   482         idx = unionFind->items[idx].nextClass;
   483         return *this;
   484       }
   485       
   486       /// \brief Conversion operator
   487       ///
   488       /// It converts the iterator to the current representant item.
   489       operator const Item&() const {
   490         return unionFind->items[idx].item;
   491       }
   492 
   493       /// \brief Equality operator
   494       ///
   495       /// Equality operator
   496       bool operator==(const ClassIt& i) { 
   497         return i.idx == idx;
   498       }
   499 
   500       /// \brief Inequality operator
   501       ///
   502       /// Inequality operator
   503       bool operator!=(const ClassIt& i) { 
   504         return i.idx != idx;
   505       }
   506       
   507     private:
   508       const UnionFindEnum* unionFind;
   509       int idx;
   510     };
   511 
   512     /// \brief Lemon style iterator for the items of a component.
   513     ///
   514     /// ClassIt is a lemon style iterator for the components. It iterates
   515     /// on the items of a class. By example if you want to iterate on
   516     /// each items of each classes then you may write the next code.
   517     ///\code
   518     /// for (ClassIt cit(ufe); cit != INVALID; ++cit) {
   519     ///   std::cout << "Class: ";
   520     ///   for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) {
   521     ///     std::cout << toString(iit) << ' ' << std::endl;
   522     ///   }
   523     ///   std::cout << std::endl;
   524     /// }
   525     ///\endcode
   526     class ItemIt {
   527     public:
   528       /// \brief Constructor of the iterator
   529       ///
   530       /// Constructor of the iterator. The iterator iterates
   531       /// on the class of the \c item.
   532       ItemIt(const UnionFindEnum& ufe, const Item& item) : unionFind(&ufe) {
   533         idx = unionFind->repIndex(unionFind->index[item]);
   534       }
   535 
   536       /// \brief Constructor to get invalid iterator
   537       ///
   538       /// Constructor to get invalid iterator
   539       ItemIt(Invalid) : unionFind(0), idx(-1) {}
   540       
   541       /// \brief Increment operator
   542       ///
   543       /// It steps to the next item in the class.
   544       ItemIt& operator++() {
   545         idx = unionFind->items[idx].nextItem;
   546         if (unionFind->rep(idx)) idx = -1;
   547         return *this;
   548       }
   549       
   550       /// \brief Conversion operator
   551       ///
   552       /// It converts the iterator to the current item.
   553       operator const Item&() const {
   554         return unionFind->items[idx].item;
   555       }
   556 
   557       /// \brief Equality operator
   558       ///
   559       /// Equality operator
   560       bool operator==(const ItemIt& i) { 
   561         return i.idx == idx;
   562       }
   563 
   564       /// \brief Inequality operator
   565       ///
   566       /// Inequality operator
   567       bool operator!=(const ItemIt& i) { 
   568         return i.idx != idx;
   569       }
   570       
   571     private:
   572       const UnionFindEnum* unionFind;
   573       int idx;
   574     };
   575 
   576   };
   577 
   578 
   579   //! @}
   580 
   581 } //namespace lemon
   582 
   583 #endif //LEMON_UNION_FIND_H