src/work/johanna/unionfind.h
author alpar
Sun, 25 Apr 2004 16:53:38 +0000
changeset 397 b4d7b19b6740
parent 349 42c660f58702
child 462 0ab31578af67
permissions -rw-r--r--
I hope it works. The 'erase' functions hasn't been tested yet.
beckerjc@150
     1
// -*- c++ -*- //
beckerjc@218
     2
#ifndef HUGO_UNION_FIND_H
beckerjc@218
     3
#define HUGO_UNION_FIND_H
beckerjc@150
     4
beckerjc@150
     5
#include <vector>
beckerjc@394
     6
#include <list>
beckerjc@150
     7
#include <utility>
beckerjc@394
     8
#include <algorithm>
beckerjc@394
     9
beckerjc@394
    10
#include <invalid.h>
beckerjc@150
    11
beckerjc@150
    12
namespace hugo {
beckerjc@150
    13
beckerjc@150
    14
  template <typename T, typename TIntMap>
beckerjc@150
    15
  class UnionFind {
beckerjc@150
    16
    
beckerjc@150
    17
  public:
beckerjc@150
    18
    typedef T ElementType;
beckerjc@150
    19
    typedef std::pair<int,int> PairType;
beckerjc@150
    20
beckerjc@150
    21
  private:
beckerjc@150
    22
    std::vector<PairType> data;
beckerjc@150
    23
    TIntMap& map;
beckerjc@150
    24
beckerjc@150
    25
  public:
beckerjc@150
    26
    UnionFind(TIntMap& m) : map(m) {}
beckerjc@150
    27
beckerjc@150
    28
beckerjc@394
    29
    int find(T a)
beckerjc@150
    30
    {
beckerjc@349
    31
      int comp0 = map[a];
beckerjc@150
    32
      if (comp0 < 0) {
beckerjc@394
    33
	return insert(a);
beckerjc@150
    34
      }
beckerjc@150
    35
      int comp = comp0;
beckerjc@150
    36
      int next;
beckerjc@150
    37
      while ( (next = data[comp].first) != comp) {
beckerjc@150
    38
	comp = next;
beckerjc@150
    39
      }
beckerjc@150
    40
      while ( (next = data[comp0].first) != comp) {
beckerjc@150
    41
	data[comp0].first = comp;
beckerjc@150
    42
	comp0 = next;
beckerjc@150
    43
      }
beckerjc@150
    44
beckerjc@150
    45
      return comp;
beckerjc@150
    46
    }
beckerjc@150
    47
beckerjc@394
    48
    int insert(T a)
beckerjc@150
    49
    {
beckerjc@150
    50
      int n = data.size();
beckerjc@394
    51
      data.push_back(std::make_pair(n, 1));
beckerjc@150
    52
      map.set(a,n);
beckerjc@150
    53
      return n;
beckerjc@150
    54
    }
beckerjc@150
    55
beckerjc@394
    56
    bool join(T a, T b)
beckerjc@150
    57
    {
beckerjc@394
    58
      int ca = find(a);
beckerjc@394
    59
      int cb = find(b);
beckerjc@150
    60
beckerjc@150
    61
      if ( ca == cb ) 
beckerjc@150
    62
	return false;
beckerjc@150
    63
beckerjc@150
    64
      if ( data[ca].second > data[cb].second ) {
beckerjc@150
    65
	data[cb].first = ca;
beckerjc@150
    66
	data[ca].second += data[cb].second;
beckerjc@150
    67
      }
beckerjc@150
    68
      else {
beckerjc@150
    69
	data[ca].first = cb;
beckerjc@150
    70
	data[cb].second += data[ca].second;
beckerjc@150
    71
      }
beckerjc@150
    72
      return true;
beckerjc@150
    73
    }
beckerjc@150
    74
beckerjc@394
    75
    int size(T a)
beckerjc@218
    76
    {
beckerjc@394
    77
      int ca = find(a);
beckerjc@218
    78
      return data[ca].second;
beckerjc@218
    79
    }
beckerjc@218
    80
beckerjc@150
    81
  };
beckerjc@150
    82
beckerjc@394
    83
beckerjc@394
    84
beckerjc@394
    85
beckerjc@394
    86
  /*******************************************************/
beckerjc@394
    87
beckerjc@394
    88
beckerjc@394
    89
beckerjc@394
    90
  template <typename T>
beckerjc@394
    91
  struct UnionFindEnumItem {
beckerjc@394
    92
beckerjc@394
    93
    typedef std::list<UnionFindEnumItem> ItemList;
beckerjc@394
    94
    typedef std::list<ItemList> ClassList;
beckerjc@394
    95
    typedef typename ItemList::iterator IIter;
beckerjc@394
    96
    typedef typename ClassList::iterator CIter;
beckerjc@394
    97
beckerjc@394
    98
    T me;
beckerjc@394
    99
    IIter parent;
beckerjc@394
   100
    int size;
beckerjc@394
   101
    CIter my_class;
beckerjc@394
   102
beckerjc@394
   103
    UnionFindEnumItem() {}
beckerjc@394
   104
    UnionFindEnumItem(const T &_me, CIter _my_class): 
beckerjc@394
   105
      me(_me), size(1), my_class(_my_class) {}
beckerjc@394
   106
  };
beckerjc@394
   107
beckerjc@394
   108
  template <typename T, template <typename Item> class Map>
beckerjc@394
   109
  class UnionFindEnum {
beckerjc@394
   110
beckerjc@394
   111
    typedef std::list<UnionFindEnumItem<T> > ItemList;
beckerjc@394
   112
    typedef std::list<ItemList> ClassList;
beckerjc@394
   113
    typedef typename ItemList::iterator IIter;
beckerjc@394
   114
    typedef typename ItemList::const_iterator IcIter;
beckerjc@394
   115
    typedef typename ClassList::iterator CIter;
beckerjc@394
   116
    typedef typename ClassList::const_iterator CcIter;
beckerjc@394
   117
beckerjc@394
   118
  public:
beckerjc@394
   119
    typedef T ElementType;
beckerjc@394
   120
    typedef UnionFindEnumItem<T> ItemType;
beckerjc@394
   121
    typedef Map< IIter > MapType;
beckerjc@394
   122
beckerjc@394
   123
  private:
beckerjc@394
   124
    MapType& m;
beckerjc@394
   125
    ClassList classes;
beckerjc@394
   126
beckerjc@394
   127
    //    IIter where(const T &a) { return m[a]; }
beckerjc@394
   128
    //    IIter parent(IIter a) { return a->parent; }
beckerjc@394
   129
    //    P sibling(P a) { return &m[a->sibling]; }
beckerjc@394
   130
beckerjc@394
   131
    IIter _find(IIter a) const {
beckerjc@394
   132
      IIter comp = a;
beckerjc@394
   133
      IIter next;
beckerjc@394
   134
      while( (next = comp->parent) != comp ) {
beckerjc@394
   135
	comp = next;
beckerjc@394
   136
      }
beckerjc@394
   137
beckerjc@394
   138
      IIter comp1 = a;
beckerjc@394
   139
      while( (next = comp1->parent) != comp ) {
beckerjc@394
   140
	comp1->parent = comp->parent;
beckerjc@394
   141
	comp1 = next;
beckerjc@394
   142
      }
beckerjc@394
   143
      return comp;
beckerjc@394
   144
    }
beckerjc@394
   145
beckerjc@394
   146
  public:
beckerjc@394
   147
    UnionFindEnum(MapType& _m) : m(_m) {}
beckerjc@394
   148
beckerjc@394
   149
    void insert(const T &a)
beckerjc@394
   150
    {
beckerjc@394
   151
beckerjc@394
   152
beckerjc@394
   153
      classes.push_back(ItemList());
beckerjc@394
   154
      CIter aclass = classes.end();
beckerjc@394
   155
      --aclass;
beckerjc@394
   156
beckerjc@394
   157
      ItemList &alist = *aclass;
beckerjc@394
   158
      alist.push_back(ItemType(a, aclass));
beckerjc@394
   159
      IIter ai = alist.begin();
beckerjc@394
   160
beckerjc@394
   161
      ai->parent = ai;
beckerjc@394
   162
      m.set(a, ai);
beckerjc@394
   163
beckerjc@394
   164
    }
beckerjc@394
   165
beckerjc@394
   166
    T find(const T &a) const {
beckerjc@394
   167
      return _find(m[a])->me;
beckerjc@394
   168
    }
beckerjc@394
   169
beckerjc@394
   170
    bool join(T a, T b) {
beckerjc@394
   171
beckerjc@394
   172
      IIter ca = _find(m[a]);
beckerjc@394
   173
      IIter cb = _find(m[b]);
beckerjc@394
   174
beckerjc@394
   175
      if ( ca == cb ) {
beckerjc@394
   176
	return false;
beckerjc@394
   177
      }
beckerjc@394
   178
beckerjc@394
   179
      if ( ca->size > cb->size ) {
beckerjc@394
   180
beckerjc@394
   181
	cb->parent = ca->parent;
beckerjc@394
   182
	ca->size += cb->size;
beckerjc@394
   183
	
beckerjc@394
   184
	ItemList &alist = *ca->my_class;
beckerjc@394
   185
	alist.splice(alist.end(),*cb->my_class);
beckerjc@394
   186
beckerjc@394
   187
	classes.erase(cb->my_class);
beckerjc@394
   188
	cb->my_class = 0;
beckerjc@394
   189
      }
beckerjc@394
   190
      else {
beckerjc@394
   191
beckerjc@394
   192
	ca->parent = cb->parent;
beckerjc@394
   193
	cb->size += ca->size;
beckerjc@394
   194
	
beckerjc@394
   195
	ItemList &blist = *cb->my_class;
beckerjc@394
   196
	blist.splice(blist.end(),*ca->my_class);
beckerjc@394
   197
beckerjc@394
   198
	classes.erase(ca->my_class);
beckerjc@394
   199
	ca->my_class = 0;
beckerjc@394
   200
      }
beckerjc@394
   201
beckerjc@394
   202
      return true;
beckerjc@394
   203
    }
beckerjc@394
   204
beckerjc@394
   205
    int size(const T &a) const {
beckerjc@394
   206
      return _find(m[a])->size;
beckerjc@394
   207
    }
beckerjc@394
   208
beckerjc@394
   209
    
beckerjc@394
   210
    void split(const T &a) {
beckerjc@394
   211
beckerjc@394
   212
      IIter ca = _find(m[a]);
beckerjc@394
   213
 
beckerjc@394
   214
      if ( ca->size == 1 )
beckerjc@394
   215
	return;
beckerjc@394
   216
      
beckerjc@394
   217
      CIter aclass = ca->my_class;
beckerjc@394
   218
beckerjc@394
   219
      for(IIter curr = ca; ++curr != aclass->end(); curr=ca) {
beckerjc@394
   220
	classes.push_back(ItemList());
beckerjc@394
   221
	CIter nl = --classes.end();
beckerjc@394
   222
	nl->splice(nl->end(), *aclass, curr);
beckerjc@394
   223
beckerjc@394
   224
	curr->size=1;
beckerjc@394
   225
	curr->parent=curr;
beckerjc@394
   226
	curr->my_class = nl;
beckerjc@394
   227
      }
beckerjc@394
   228
beckerjc@394
   229
      ca->size=1;
beckerjc@394
   230
      return;
beckerjc@394
   231
    }
beckerjc@394
   232
beckerjc@394
   233
    void erase(const T &a) {
beckerjc@394
   234
beckerjc@394
   235
      IIter ma = m[a];
beckerjc@394
   236
      if (ma == 0) return;
beckerjc@394
   237
beckerjc@394
   238
      IIter la = _find(ma);
beckerjc@394
   239
      if (la == ma) {
beckerjc@394
   240
	if (ma -> size == 1){
beckerjc@394
   241
	  classes.erase(ma->my_class);
beckerjc@394
   242
	  m.set(a,0);
beckerjc@394
   243
	  return;
beckerjc@394
   244
	}
beckerjc@394
   245
	++la;
beckerjc@394
   246
	la->size = ma->size - 1; 
beckerjc@394
   247
	la->my_class = ma->my_class;	
beckerjc@394
   248
      }
beckerjc@394
   249
beckerjc@394
   250
      for (IIter i = la; i != la->my_class->end(); ++i) {
beckerjc@394
   251
	i->parent = la;
beckerjc@394
   252
      }
beckerjc@394
   253
beckerjc@394
   254
      la->my_class->erase(ma);
beckerjc@394
   255
      m.set(a,0);
beckerjc@394
   256
    }
beckerjc@394
   257
beckerjc@394
   258
    void eraseClass(const T &a) {
beckerjc@394
   259
      IIter ma = m[a];
beckerjc@394
   260
      if (ma == 0) return;
beckerjc@394
   261
#     ifdef DEBUG
beckerjc@394
   262
      CIter c = _find(ma)->my_class;
beckerjc@394
   263
      for (IIter i=c->begin(); i!=c->end(); ++i)
beckerjc@394
   264
	m.set(i->me, 0);
beckerjc@394
   265
#     endif
beckerjc@394
   266
      classes.erase(_find(ma)->my_class);
beckerjc@394
   267
    }
beckerjc@394
   268
beckerjc@394
   269
beckerjc@394
   270
    class ClassIt {
beckerjc@394
   271
      friend class UnionFindEnum;
beckerjc@394
   272
beckerjc@394
   273
      CcIter i;
beckerjc@394
   274
    public:
beckerjc@394
   275
      ClassIt(Invalid): i(0) {}
beckerjc@394
   276
      ClassIt() {}
beckerjc@394
   277
      
beckerjc@394
   278
      operator const T& () const { 
beckerjc@394
   279
	ItemList const &ll = *i;
beckerjc@394
   280
	return (ll.begin())->me; }
beckerjc@394
   281
      bool operator == (ClassIt it) const {
beckerjc@394
   282
	return (i == it.i);
beckerjc@394
   283
      }
beckerjc@394
   284
      bool operator != (ClassIt it) const {
beckerjc@394
   285
	return (i != it.i);
beckerjc@394
   286
      }
beckerjc@394
   287
      bool operator < (ClassIt it) const {
beckerjc@394
   288
	return (i < it.i);
beckerjc@394
   289
      }
beckerjc@394
   290
beckerjc@394
   291
      bool valid() const { return i != 0; }
beckerjc@394
   292
    private:
beckerjc@394
   293
      void first(const ClassList &l) { i = l.begin(); validate(l); }
beckerjc@394
   294
      void next(const ClassList &l) {
beckerjc@394
   295
	++i; 
beckerjc@394
   296
	validate(l);
beckerjc@394
   297
      }
beckerjc@394
   298
      void validate(const ClassList &l) {
beckerjc@394
   299
	if ( i == l.end() ) 
beckerjc@394
   300
	  i = 0;
beckerjc@394
   301
      }
beckerjc@394
   302
    };
beckerjc@394
   303
beckerjc@394
   304
beckerjc@394
   305
    ClassIt& first(ClassIt& it) const {
beckerjc@394
   306
      it.first(classes);
beckerjc@394
   307
      return it;
beckerjc@394
   308
    }
beckerjc@394
   309
beckerjc@394
   310
    bool valid(ClassIt const &it) const {
beckerjc@394
   311
      return it.valid(); 
beckerjc@394
   312
    }
beckerjc@394
   313
beckerjc@394
   314
    ClassIt& next(ClassIt& it) const {
beckerjc@394
   315
      it.next(classes);
beckerjc@394
   316
      return it;
beckerjc@394
   317
    }
beckerjc@394
   318
beckerjc@394
   319
beckerjc@394
   320
    class ItemIt {
beckerjc@394
   321
      friend class UnionFindEnum;
beckerjc@394
   322
beckerjc@394
   323
      IcIter i;
beckerjc@394
   324
      const ItemList *l;
beckerjc@394
   325
    public:
beckerjc@394
   326
      ItemIt(Invalid): i(0) {}
beckerjc@394
   327
      ItemIt() {}
beckerjc@394
   328
      
beckerjc@394
   329
      operator const T& () const { return i->me; }
beckerjc@394
   330
      bool operator == (ItemIt it) const {
beckerjc@394
   331
	return (i == it.i);
beckerjc@394
   332
      }
beckerjc@394
   333
      bool operator != (ItemIt it) const {
beckerjc@394
   334
	return (i != it.i);
beckerjc@394
   335
      }
beckerjc@394
   336
      bool operator < (ItemIt it) const {
beckerjc@394
   337
	return (i < it.i);
beckerjc@394
   338
      }
beckerjc@394
   339
beckerjc@394
   340
      bool valid() const { return i != 0; }
beckerjc@394
   341
    private:
beckerjc@394
   342
      void first(const ItemList &il) { l=&il; i = l->begin(); validate(); }
beckerjc@394
   343
      void next() {
beckerjc@394
   344
	++i; 
beckerjc@394
   345
	validate();
beckerjc@394
   346
      }
beckerjc@394
   347
      void validate() {
beckerjc@394
   348
	if ( i == l->end() ) 
beckerjc@394
   349
	  i = 0;
beckerjc@394
   350
      }
beckerjc@394
   351
    };
beckerjc@394
   352
beckerjc@394
   353
beckerjc@394
   354
    ItemIt& first(ItemIt& it, const T& a) const {
beckerjc@394
   355
      it.first( * _find(m[a])->my_class );
beckerjc@394
   356
      return it;
beckerjc@394
   357
    }
beckerjc@394
   358
beckerjc@394
   359
    bool valid(ItemIt const &it) const {
beckerjc@394
   360
      return it.valid(); 
beckerjc@394
   361
    }
beckerjc@394
   362
beckerjc@394
   363
    ItemIt& next(ItemIt& it) const {
beckerjc@394
   364
      it.next();
beckerjc@394
   365
      return it;
beckerjc@394
   366
    }
beckerjc@394
   367
    
beckerjc@394
   368
beckerjc@394
   369
beckerjc@394
   370
  };
beckerjc@394
   371
beckerjc@150
   372
} //namespace hugo
beckerjc@150
   373
beckerjc@218
   374
#endif //HUGO_UNION_FIND_H