src/work/jacint/fib_heap.h
author marci
Wed, 17 Mar 2004 16:10:33 +0000
changeset 196 8a9b9360463e
parent 167 7949a29a334e
child 211 9222a9b8b323
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) {
jacint@167
    97
      int i=iimap.get(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) {
jacint@167
   106
      int i=iimap.get(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
jacint@167
   146
    const PrioType get(const Item& it) const {
jacint@173
   147
      return container[iimap.get(it)].prio;
jacint@167
   148
    }
jacint@167
   149
jacint@167
   150
jacint@167
   151
    void pop() {
jacint@167
   152
      /*The first case is that there are only one root.*/
jacint@167
   153
      if ( container[minimum].left_neighbor==minimum ) {
jacint@167
   154
	container[minimum].in=false;
jacint@173
   155
	if ( container[minimum].degree!=0 ) { 
jacint@167
   156
	  makeroot(container[minimum].child);
jacint@167
   157
	  minimum=container[minimum].child;
jacint@167
   158
	  balance();
jacint@173
   159
	}
jacint@167
   160
      } else {
jacint@167
   161
	int right=container[minimum].right_neighbor;
jacint@167
   162
	unlace(minimum);
jacint@167
   163
	container[minimum].in=false;
jacint@167
   164
	if ( container[minimum].degree > 0 ) {
jacint@167
   165
	  int left=container[minimum].left_neighbor;
jacint@167
   166
	  int child=container[minimum].child;
jacint@167
   167
	  int last_child=container[child].left_neighbor;
jacint@167
   168
	
jacint@167
   169
	  makeroot(child);
jacint@167
   170
	  
jacint@167
   171
	  container[left].right_neighbor=child;
jacint@167
   172
	  container[child].left_neighbor=left;
jacint@167
   173
	  container[right].left_neighbor=last_child;
jacint@167
   174
	  container[last_child].right_neighbor=right;
jacint@167
   175
	}
jacint@167
   176
	minimum=right;
jacint@167
   177
	balance();
jacint@167
   178
      } // the case where there are more roots
jacint@173
   179
      --num_items;   
jacint@167
   180
    }
jacint@167
   181
jacint@167
   182
    
jacint@167
   183
    void erase (const Item& it) {
jacint@167
   184
      int i=iimap.get(it);
jacint@167
   185
      
jacint@173
   186
      if ( i >= 0 && container[i].in ) { 	
jacint@173
   187
	if ( container[i].parent!=-1 ) {
jacint@173
   188
	  int p=container[i].parent;
jacint@173
   189
	  cut(i,p);	    
jacint@173
   190
	  cascade(p);
jacint@173
   191
	}
jacint@173
   192
	minimum=i;     //As if its prio would be -infinity
jacint@173
   193
	pop();
jacint@173
   194
      }
jacint@173
   195
    }
jacint@167
   196
    
jacint@167
   197
jacint@167
   198
    void decrease (Item it, PrioType const value) {
jacint@167
   199
      int i=iimap.get(it);
jacint@167
   200
      container[i].prio=value;
jacint@167
   201
      int p=container[i].parent;
jacint@167
   202
      
jacint@167
   203
      if ( p!=-1 && comp(value, container[p].prio) ) {
jacint@167
   204
	cut(i,p);	    
jacint@167
   205
	cascade(p);
jacint@173
   206
      }      
jacint@173
   207
      if ( comp(value, container[minimum].prio) ) minimum=i; 
jacint@167
   208
    }
jacint@167
   209
   
jacint@167
   210
jacint@167
   211
    void increase (Item it, PrioType const value) {
jacint@167
   212
      erase(it);
jacint@167
   213
      push(it, value);
jacint@167
   214
    }
jacint@167
   215
jacint@167
   216
jacint@167
   217
    state_enum state(const Item &it) const {
jacint@167
   218
      int i=iimap.get(it);
jacint@167
   219
      if( i>=0 ) {
jacint@167
   220
	if ( container[i].in ) i=0;
jacint@167
   221
	else i=-2; 
jacint@167
   222
      }
jacint@167
   223
      return state_enum(i);
jacint@167
   224
    }
jacint@167
   225
jacint@167
   226
jacint@167
   227
  private:
jacint@167
   228
    
jacint@167
   229
    void balance() {      
jacint@167
   230
jacint@167
   231
    int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
jacint@167
   232
  
jacint@167
   233
    std::vector<int> A(maxdeg,-1); 
jacint@167
   234
    
jacint@167
   235
    /*
jacint@167
   236
     *Recall that now minimum does not point to the minimum prio element.
jacint@167
   237
     *We set minimum to this during balance().
jacint@167
   238
     */
jacint@167
   239
    int anchor=container[minimum].left_neighbor; 
jacint@167
   240
    int next=minimum; 
jacint@167
   241
    bool end=false; 
jacint@167
   242
    	
jacint@167
   243
       do {
jacint@167
   244
	int active=next;
jacint@167
   245
	if ( anchor==active ) end=true;
jacint@167
   246
	int d=container[active].degree;
jacint@167
   247
	next=container[active].right_neighbor;
jacint@167
   248
jacint@167
   249
	while (A[d]!=-1) {	  
jacint@167
   250
	  if( comp(container[active].prio, container[A[d]].prio) ) {
jacint@167
   251
	    fuse(active,A[d]); 
jacint@167
   252
	  } else { 
jacint@167
   253
	    fuse(A[d],active);
jacint@167
   254
	    active=A[d];
jacint@167
   255
	  } 
jacint@167
   256
	  A[d]=-1;
jacint@167
   257
	  ++d;
jacint@167
   258
	}	
jacint@167
   259
	A[d]=active;
jacint@167
   260
       } while ( !end );
jacint@167
   261
jacint@167
   262
jacint@167
   263
       while ( container[minimum].parent >=0 ) minimum=container[minimum].parent;
jacint@167
   264
       int s=minimum;
jacint@167
   265
       int m=minimum;
jacint@167
   266
       do {  
jacint@167
   267
	 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s;
jacint@167
   268
	 s=container[s].right_neighbor;
jacint@167
   269
       } while ( s != m );
jacint@167
   270
    }
jacint@167
   271
jacint@167
   272
jacint@167
   273
    void makeroot (int c) {
jacint@167
   274
      int s=c;
jacint@167
   275
      do {  
jacint@167
   276
	container[s].parent=-1;
jacint@167
   277
	s=container[s].right_neighbor;
jacint@167
   278
      } while ( s != c );
jacint@167
   279
    }
jacint@167
   280
    
jacint@167
   281
jacint@167
   282
    void cut (int a, int b) {    
jacint@167
   283
      /*
jacint@167
   284
       *Replacing a from the children of b.
jacint@167
   285
       */
jacint@167
   286
      --container[b].degree;
jacint@167
   287
      
jacint@167
   288
      if ( container[b].degree !=0 ) {
jacint@167
   289
	int child=container[b].child;
jacint@167
   290
	if ( child==a ) 
jacint@167
   291
	  container[b].child=container[child].right_neighbor;
jacint@167
   292
	unlace(a);
jacint@167
   293
      }
jacint@167
   294
      
jacint@167
   295
      
jacint@173
   296
      /*Lacing a to the roots.*/
jacint@167
   297
      int right=container[minimum].right_neighbor;
jacint@167
   298
      container[minimum].right_neighbor=a;
jacint@167
   299
      container[a].left_neighbor=minimum;
jacint@167
   300
      container[a].right_neighbor=right;
jacint@167
   301
      container[right].left_neighbor=a;
jacint@167
   302
jacint@167
   303
      container[a].parent=-1;
jacint@167
   304
      container[a].marked=false;
jacint@167
   305
    }
jacint@167
   306
jacint@167
   307
jacint@167
   308
    void cascade (int a) 
jacint@167
   309
    {
jacint@167
   310
      if ( container[a].parent!=-1 ) {
jacint@167
   311
	int p=container[a].parent;
jacint@167
   312
	
jacint@167
   313
	if ( container[a].marked==false ) container[a].marked=true;
jacint@167
   314
	else {
jacint@167
   315
	  cut(a,p);
jacint@167
   316
	  cascade(p);
jacint@167
   317
	}
jacint@167
   318
      }
jacint@167
   319
    }
jacint@167
   320
jacint@167
   321
jacint@167
   322
    void fuse (int a, int b) {
jacint@167
   323
      unlace(b);
jacint@167
   324
      
jacint@167
   325
      /*Lacing b under a.*/
jacint@167
   326
      container[b].parent=a;
jacint@167
   327
jacint@167
   328
      if (container[a].degree==0) {
jacint@167
   329
	container[b].left_neighbor=b;
jacint@167
   330
	container[b].right_neighbor=b;
jacint@167
   331
	container[a].child=b;	
jacint@167
   332
      } else {
jacint@167
   333
	int child=container[a].child;
jacint@167
   334
	int last_child=container[child].left_neighbor;
jacint@167
   335
	container[child].left_neighbor=b;
jacint@167
   336
	container[b].right_neighbor=child;
jacint@167
   337
	container[last_child].right_neighbor=b;
jacint@167
   338
	container[b].left_neighbor=last_child;
jacint@167
   339
      }
jacint@167
   340
jacint@167
   341
      ++container[a].degree;
jacint@167
   342
      
jacint@167
   343
      container[b].marked=false;
jacint@167
   344
    }
jacint@167
   345
jacint@167
   346
jacint@167
   347
    /*
jacint@167
   348
     *It is invoked only if a has siblings.
jacint@167
   349
     */
jacint@167
   350
    void unlace (int a) {      
jacint@167
   351
      int leftn=container[a].left_neighbor;
jacint@167
   352
      int rightn=container[a].right_neighbor;
jacint@167
   353
      container[leftn].right_neighbor=rightn;
jacint@167
   354
      container[rightn].left_neighbor=leftn;
jacint@167
   355
    }
jacint@167
   356
jacint@167
   357
jacint@167
   358
    class store {
jacint@167
   359
      friend class FibHeap;
jacint@167
   360
      
jacint@167
   361
      Item name;
jacint@167
   362
      int parent;
jacint@167
   363
      int left_neighbor;
jacint@167
   364
      int right_neighbor;
jacint@167
   365
      int child;
jacint@167
   366
      int degree;  
jacint@167
   367
      bool marked;
jacint@167
   368
      bool in;
jacint@167
   369
      PrioType prio;
jacint@167
   370
jacint@167
   371
      store() : parent(-1), child(-1), degree(), marked(false), in(true) {} 
jacint@167
   372
    };
jacint@167
   373
    
jacint@167
   374
  };
jacint@167
   375
  
jacint@167
   376
} //namespace hugo
jacint@167
   377
#endif