src/work/jacint/fib_heap.h
author jacint
Tue, 09 Mar 2004 15:53:19 +0000
changeset 160 f1a7005e9dff
child 161 743fa50c442e
permissions -rw-r--r--
*** empty log message ***
jacint@159
     1
// -*- C++ -*-
jacint@159
     2
/*
jacint@159
     3
 *template <typename Item, 
jacint@159
     4
 *          typename Prio, 
jacint@159
     5
 *          typename ItemIntMap, 
jacint@159
     6
 *          typename Compare = std::less<Prio> >
jacint@159
     7
 * 
jacint@159
     8
 *constructors:
jacint@159
     9
 *
jacint@159
    10
 *FibHeap(ItemIntMap),   FibHeap(ItemIntMap, Compare)
jacint@159
    11
 *
jacint@159
    12
 *Member functions:
jacint@159
    13
 *
jacint@159
    14
 *int size() : returns the number of elements in the heap
jacint@159
    15
 *
jacint@159
    16
 *bool empty() : true iff size()=0
jacint@159
    17
 *
jacint@159
    18
 *void push(Item, Prio) : pushes Item to the heap with priority Prio. If
jacint@159
    19
 *     Item was already in the heap, it calls decrease(Item, Prio) 
jacint@159
    20
 *
jacint@159
    21
 *Item top() : returns the Item with least Prio
jacint@159
    22
 *
jacint@159
    23
 *Prio prio() : returns the least Prio
jacint@159
    24
 *  
jacint@159
    25
 *Prio get(Item) : returns Prio of Item
jacint@159
    26
 *
jacint@159
    27
 *void pop() : deletes the Item with least Prio
jacint@159
    28
 *
jacint@159
    29
 *void erase(Item) : deletes Item from the heap if it was already there
jacint@159
    30
 *
jacint@159
    31
 *void decrease(Item, P) : If Item was not in the heap, then it calls 
jacint@159
    32
 *     push(Item, P). If item is in the heap with Prio more than P
jacint@159
    33
 *     then sets its Prio to P.
jacint@159
    34
 *
jacint@159
    35
 *void increase(Item, P) : If Item was not in the heap, then it calls 
jacint@159
    36
 *     push(Item, P). If item is in the heap with Prio less than P
jacint@159
    37
 *     then sets its Prio to P.
jacint@159
    38
 *
jacint@159
    39
 *
jacint@159
    40
 *In Fibonacci heaps, increase and erase are not efficient, in case of
jacint@159
    41
 *many calls to these operations, it is better to use bin_heap.
jacint@159
    42
 */
jacint@159
    43
jacint@159
    44
#ifndef FIB_HEAP_H
jacint@159
    45
#define FIB_HEAP_H
jacint@159
    46
jacint@159
    47
#include <vector>
jacint@159
    48
#include <functional>
jacint@159
    49
#include <math.h>
jacint@159
    50
jacint@159
    51
namespace hugo {
jacint@159
    52
  
jacint@159
    53
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@159
    54
    typename Compare = std::less<Prio> >
jacint@159
    55
 
jacint@159
    56
  class FibHeap {
jacint@159
    57
  
jacint@159
    58
    typedef Prio PrioType;
jacint@159
    59
    
jacint@159
    60
    class store;
jacint@159
    61
    
jacint@159
    62
    std::vector<store> container;
jacint@159
    63
    int minimum;
jacint@159
    64
    bool blank;
jacint@159
    65
    ItemIntMap &iimap;
jacint@159
    66
    Compare comp;
jacint@159
    67
    
jacint@159
    68
  public :
jacint@159
    69
    
jacint@159
    70
    FibHeap(ItemIntMap &_iimap) : minimum(), blank(true), iimap(_iimap) {} 
jacint@159
    71
    FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(), 
jacint@159
    72
      blank(true), iimap(_iimap), comp(_comp) {}
jacint@159
    73
    
jacint@159
    74
    
jacint@159
    75
    int size() const {
jacint@159
    76
      int s=0;
jacint@159
    77
      for ( unsigned int i=0; i!=container.size(); ++i )
jacint@159
    78
	if ( container[i].in ) ++s;
jacint@159
    79
      return s; 
jacint@159
    80
    }
jacint@159
    81
jacint@159
    82
jacint@159
    83
   bool empty() const { return blank; }
jacint@159
    84
    
jacint@159
    85
    
jacint@159
    86
   void push (Item const it, PrioType const value) 
jacint@159
    87
   {
jacint@159
    88
   
jacint@159
    89
     int i=iimap.get(it);
jacint@159
    90
      
jacint@159
    91
     if ( i >= 0 && container[i].in ) decrease(it, value); 
jacint@159
    92
     else {
jacint@159
    93
       if ( i < 0 ) {
jacint@159
    94
	 int s=container.size();
jacint@159
    95
	 iimap.set( it, s );	
jacint@159
    96
	 store st;
jacint@159
    97
	 st.name=it;
jacint@159
    98
	 container.push_back(st);
jacint@159
    99
	 i=s;
jacint@159
   100
       }
jacint@159
   101
       
jacint@159
   102
       if ( !blank ) {
jacint@159
   103
	 container[container[minimum].right_neighbor].left_neighbor=i;
jacint@159
   104
	 container[i].right_neighbor=container[minimum].right_neighbor;
jacint@159
   105
	 container[minimum].right_neighbor=i;
jacint@159
   106
	 container[i].left_neighbor=minimum;
jacint@159
   107
	 if ( !comp( container[minimum].prio, value) ) minimum=i; 
jacint@159
   108
jacint@159
   109
jacint@159
   110
jacint@159
   111
       } else {
jacint@159
   112
	 container[i].right_neighbor=container[i].left_neighbor=i;
jacint@159
   113
	 minimum=i;	
jacint@159
   114
	 blank=false;
jacint@159
   115
       }
jacint@159
   116
       container[i].prio=value;
jacint@159
   117
     }
jacint@159
   118
   }
jacint@159
   119
jacint@159
   120
jacint@159
   121
    Item top() const {
jacint@159
   122
      if ( !blank ) { 
jacint@159
   123
	return container[minimum].name;
jacint@159
   124
      } else {
jacint@159
   125
	return Item();
jacint@159
   126
      }
jacint@159
   127
    }
jacint@159
   128
    
jacint@159
   129
    
jacint@159
   130
    PrioType prio() const {
jacint@159
   131
      if ( !blank ) { 
jacint@159
   132
	return container[minimum].prio;
jacint@159
   133
      } else {
jacint@159
   134
	return PrioType();
jacint@159
   135
      }
jacint@159
   136
    }
jacint@159
   137
    
jacint@159
   138
jacint@159
   139
    const PrioType get(const Item& it) const
jacint@159
   140
    {
jacint@159
   141
      int i=iimap.get(it);
jacint@159
   142
      
jacint@159
   143
      if ( i >= 0 && container[i].in ) { 
jacint@159
   144
	return container[i].prio;
jacint@159
   145
      } else {
jacint@159
   146
	return PrioType();
jacint@159
   147
      }
jacint@159
   148
    }
jacint@159
   149
jacint@159
   150
jacint@159
   151
    void pop() {
jacint@159
   152
      if ( !blank ) {
jacint@159
   153
	
jacint@159
   154
	/*The first case is that there are only one root.*/
jacint@159
   155
	if ( container[minimum].left_neighbor==minimum ) {
jacint@159
   156
	  container[minimum].in=false;
jacint@159
   157
	  if ( container[minimum].degree==0 ) blank=true; 
jacint@159
   158
	  else { 
jacint@159
   159
	    makeroot(container[minimum].child);
jacint@159
   160
	    minimum=container[minimum].child;
jacint@159
   161
	    balance();
jacint@159
   162
	  } 
jacint@159
   163
       } else {
jacint@159
   164
	 int right=container[minimum].right_neighbor;
jacint@159
   165
	 unlace(minimum);
jacint@159
   166
	 container[minimum].in=false;
jacint@159
   167
	 if ( container[minimum].degree > 0 ) {
jacint@159
   168
	   int left=container[minimum].left_neighbor;
jacint@159
   169
	   int child=container[minimum].child;
jacint@159
   170
	   int last_child=container[child].left_neighbor;
jacint@159
   171
	   
jacint@159
   172
	   container[left].right_neighbor=child;
jacint@159
   173
	   container[child].left_neighbor=left;
jacint@159
   174
	   container[right].left_neighbor=last_child;
jacint@159
   175
	   container[last_child].right_neighbor=right;
jacint@159
   176
	   
jacint@159
   177
	   makeroot(child);
jacint@159
   178
	 }
jacint@159
   179
	 minimum=right;
jacint@159
   180
	 balance();
jacint@159
   181
       } // the case where there are more roots
jacint@159
   182
     } 
jacint@159
   183
   }
jacint@159
   184
jacint@159
   185
    
jacint@159
   186
   void erase (const Item& it) {
jacint@159
   187
     int i=iimap.get(it);
jacint@159
   188
     
jacint@159
   189
     if ( i >= 0 && container[i].in ) { 
jacint@159
   190
	
jacint@159
   191
       if ( container[i].parent!=-1 ) {
jacint@159
   192
	 int p=container[i].parent;
jacint@159
   193
	 cut(i,p);	    
jacint@159
   194
	 cascade(p);
jacint@159
   195
	 minimum=i;     //As if its prio would be -infinity
jacint@159
   196
       }
jacint@159
   197
       pop();
jacint@159
   198
     }
jacint@159
   199
   }
jacint@159
   200
    
jacint@159
   201
jacint@159
   202
   void decrease (Item it, PrioType const value) {
jacint@159
   203
     int i=iimap.get(it);
jacint@159
   204
     if ( i >= 0 && container[i].in ) { 
jacint@159
   205
       
jacint@159
   206
       if ( comp(value, container[i].prio) ) {
jacint@159
   207
	 container[i].prio=value;
jacint@159
   208
	 
jacint@159
   209
	 if ( container[i].parent!=-1 ) {
jacint@159
   210
	   int p=container[i].parent;
jacint@159
   211
	    
jacint@159
   212
	   if ( !comp(container[p].prio, value) ) { 
jacint@159
   213
	     cut(i,p);	    
jacint@159
   214
	     cascade(p);
jacint@159
   215
	     if ( comp(value, container[minimum].prio) ) minimum=i; 
jacint@159
   216
	   }
jacint@159
   217
	 } 
jacint@159
   218
       }
jacint@159
   219
     } else push(it, value);
jacint@159
   220
   }
jacint@159
   221
   
jacint@159
   222
jacint@159
   223
    void increase (Item it, PrioType const value) {
jacint@159
   224
      int i=iimap.get(it);
jacint@159
   225
      
jacint@159
   226
      if ( i >= 0 && container[i].in ) { 
jacint@159
   227
	if ( comp(container[i].prio, value) ) { 
jacint@159
   228
	  erase(it);
jacint@159
   229
	  push(it, value);
jacint@159
   230
	}
jacint@159
   231
      } else push(it, value);
jacint@159
   232
    }
jacint@159
   233
jacint@159
   234
jacint@159
   235
  private:
jacint@159
   236
    
jacint@159
   237
    void balance() {      
jacint@159
   238
    int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
jacint@159
   239
  
jacint@159
   240
    std::vector<int> A(maxdeg,-1); 
jacint@159
   241
    
jacint@159
   242
    /*
jacint@159
   243
     *Recall that now minimum does not point to the minimum prio element.
jacint@159
   244
     *We set minimum to this during balance().
jacint@159
   245
     */
jacint@159
   246
    int anchor=container[minimum].left_neighbor; 
jacint@159
   247
    int next=minimum; 
jacint@159
   248
    bool end=false; 
jacint@159
   249
    	
jacint@159
   250
       do {
jacint@159
   251
	int active=next;
jacint@159
   252
	int d=container[active].degree;
jacint@159
   253
	if ( anchor==active ) end=true;
jacint@159
   254
	next = container[active].right_neighbor;
jacint@159
   255
	if ( !comp(container[minimum].prio, container[active].prio) )
jacint@159
   256
	  minimum=active;
jacint@159
   257
jacint@159
   258
	while (A[d]!=-1) {
jacint@159
   259
	  
jacint@159
   260
	  if( comp(container[active].prio, container[A[d]].prio) ) {
jacint@159
   261
	    fuse(active,A[d]); 
jacint@159
   262
	  } else { 
jacint@159
   263
	    fuse(A[d],active);
jacint@159
   264
	    active=A[d];
jacint@159
   265
	  } 
jacint@159
   266
	  A[d]=-1;
jacint@159
   267
	  ++d;
jacint@159
   268
	}
jacint@159
   269
	
jacint@159
   270
	A[d]=active;
jacint@159
   271
       } while ( !end );
jacint@159
   272
  }
jacint@159
   273
jacint@159
   274
jacint@159
   275
jacint@159
   276
jacint@159
   277
    /*
jacint@159
   278
     *All the siblings of a are made roots.
jacint@159
   279
     */
jacint@159
   280
    void makeroot (int c)  
jacint@159
   281
    {
jacint@159
   282
      int s=c;
jacint@159
   283
      do {  
jacint@159
   284
	container[s].parent=-1;
jacint@159
   285
	s=container[s].right_neighbor;
jacint@159
   286
      } while ( s != c );
jacint@159
   287
    }
jacint@159
   288
    
jacint@159
   289
jacint@159
   290
    void cut (int a, int b) 
jacint@159
   291
    {    
jacint@159
   292
jacint@159
   293
      /*
jacint@159
   294
       *Replacing a from the children of b.
jacint@159
   295
       */
jacint@159
   296
      --container[b].degree;
jacint@159
   297
jacint@159
   298
      if ( container[b].degree !=0 ) {
jacint@159
   299
      int child=container[b].child;
jacint@159
   300
      if ( child==a ) 
jacint@159
   301
	container[b].child=container[child].right_neighbor;
jacint@159
   302
      
jacint@159
   303
      unlace(a);
jacint@159
   304
	
jacint@159
   305
      }
jacint@159
   306
    
jacint@159
   307
jacint@159
   308
      /*Lacing i to the roots.*/
jacint@159
   309
      int right=container[minimum].right_neighbor;
jacint@159
   310
      container[minimum].right_neighbor=a;
jacint@159
   311
      container[a].left_neighbor=minimum;
jacint@159
   312
      container[a].right_neighbor=right;
jacint@159
   313
      container[right].left_neighbor=a;
jacint@159
   314
jacint@159
   315
      container[a].parent=-1;
jacint@159
   316
      container[a].marked=false;
jacint@159
   317
    }
jacint@159
   318
jacint@159
   319
jacint@159
   320
    void cascade (int a) 
jacint@159
   321
    {
jacint@159
   322
      if ( container[a].parent!=-1 ) {
jacint@159
   323
	int p=container[a].parent;
jacint@159
   324
	
jacint@159
   325
	if ( container[a].marked==false ) container[a].marked=true;
jacint@159
   326
	else {
jacint@159
   327
	  cut(a,p);
jacint@159
   328
	  cascade(p);
jacint@159
   329
	}
jacint@159
   330
      }
jacint@159
   331
    }
jacint@159
   332
jacint@159
   333
jacint@159
   334
    void fuse (int a, int b) 
jacint@159
   335
    {
jacint@159
   336
      
jacint@159
   337
      unlace(b);
jacint@159
   338
jacint@159
   339
      
jacint@159
   340
      /*Lacing b under a.*/
jacint@159
   341
      container[b].parent=a;
jacint@159
   342
jacint@159
   343
      if (container[a].degree==0) {
jacint@159
   344
	container[b].left_neighbor=b;
jacint@159
   345
	container[b].right_neighbor=b;
jacint@159
   346
	container[a].child=b;	
jacint@159
   347
      } else {
jacint@159
   348
	int child=container[a].child;
jacint@159
   349
	int last_child=container[child].left_neighbor;
jacint@159
   350
	container[child].left_neighbor=b;
jacint@159
   351
	container[b].right_neighbor=child;
jacint@159
   352
	container[last_child].right_neighbor=b;
jacint@159
   353
	container[b].left_neighbor=last_child;
jacint@159
   354
      }
jacint@159
   355
jacint@159
   356
      ++container[a].degree;
jacint@159
   357
      
jacint@159
   358
      container[b].marked=false;
jacint@159
   359
    }
jacint@159
   360
jacint@159
   361
jacint@159
   362
    /*
jacint@159
   363
     *It is invoked only if a has siblings.
jacint@159
   364
     */
jacint@159
   365
jacint@159
   366
    void unlace (int a) {      
jacint@159
   367
      int leftn=container[a].left_neighbor;
jacint@159
   368
      int rightn=container[a].right_neighbor;
jacint@159
   369
      container[leftn].right_neighbor=rightn;
jacint@159
   370
      container[rightn].left_neighbor=leftn;
jacint@159
   371
    }
jacint@159
   372
jacint@159
   373
jacint@159
   374
    class store {
jacint@159
   375
      friend class FibHeap;
jacint@159
   376
      
jacint@159
   377
      Item name;
jacint@159
   378
      int parent;
jacint@159
   379
      int left_neighbor;
jacint@159
   380
      int right_neighbor;
jacint@159
   381
      int child;
jacint@159
   382
      int degree;  
jacint@159
   383
      bool marked;
jacint@159
   384
      bool in;
jacint@159
   385
      PrioType prio;
jacint@159
   386
jacint@159
   387
      store() : parent(-1), child(-1), degree(), marked(false), in(true) {} 
jacint@159
   388
    };
jacint@159
   389
    
jacint@159
   390
  };
jacint@159
   391
  
jacint@159
   392
} //namespace hugo
jacint@159
   393
#endif 
jacint@159
   394
jacint@159
   395
jacint@159
   396
jacint@159
   397
jacint@159
   398
jacint@159
   399