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