src/work/jacint/fib_heap.h
author alpar
Wed, 10 Mar 2004 16:43:50 +0000
changeset 162 abfae454c3b5
parent 159 0defa5aa1229
permissions -rw-r--r--
Declarations and definitions of Invalid and INVALID
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@161
    18
 *void set(Item, Prio) : calls push(Item, Prio) if Item is not
jacint@161
    19
 *     in the heap, and calls decrease/increase(Item, Prio) otherwise
jacint@161
    20
 *
jacint@161
    21
 *void push(Item, Prio) : pushes Item to the heap with priority Prio. Item
jacint@161
    22
 *     mustn't be in the heap.
jacint@159
    23
 *
jacint@159
    24
 *Item top() : returns the Item with least Prio
jacint@159
    25
 *
jacint@159
    26
 *Prio prio() : returns the least Prio
jacint@159
    27
 *  
jacint@159
    28
 *Prio get(Item) : returns Prio of Item
jacint@159
    29
 *
jacint@159
    30
 *void pop() : deletes the Item with least Prio
jacint@159
    31
 *
jacint@159
    32
 *void erase(Item) : deletes Item from the heap if it was already there
jacint@159
    33
 *
jacint@161
    34
 *void decrease(Item, P) : decreases prio of Item to P. Item must be in the heap 
jacint@161
    35
 *     with prio at least P.
jacint@159
    36
 *
jacint@161
    37
 *void increase(Item, P) : sets prio of Item 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@161
    83
    bool empty() const { return blank; }
jacint@161
    84
jacint@161
    85
jacint@161
    86
    void set (Item const it, PrioType const value) {
jacint@161
    87
      int i=iimap.get(it);
jacint@161
    88
      if ( i >= 0 && container[i].in ) {
jacint@161
    89
	if ( !comp(container[i].prio, value) ) decrease(it, value); 
jacint@161
    90
	if ( comp(container[i].prio, value) ) increase(it, value); 
jacint@161
    91
      } else push(it, value);
jacint@161
    92
    }
jacint@159
    93
    
jacint@161
    94
jacint@161
    95
    void push (Item const it, PrioType const value) {
jacint@161
    96
      int i=iimap.get(it);      
jacint@161
    97
      if ( i < 0 ) {
jacint@161
    98
	int s=container.size();
jacint@161
    99
	iimap.set( it, s );	
jacint@161
   100
	store st;
jacint@161
   101
	st.name=it;
jacint@161
   102
	container.push_back(st);
jacint@161
   103
	i=s;
jacint@161
   104
      }
jacint@161
   105
      
jacint@161
   106
      if ( !blank ) {
jacint@161
   107
	container[container[minimum].right_neighbor].left_neighbor=i;
jacint@161
   108
	container[i].right_neighbor=container[minimum].right_neighbor;
jacint@161
   109
	container[minimum].right_neighbor=i;
jacint@161
   110
	container[i].left_neighbor=minimum;
jacint@161
   111
	if ( !comp( container[minimum].prio, value) ) minimum=i; 
jacint@161
   112
	
jacint@161
   113
      } else {
jacint@161
   114
	container[i].right_neighbor=container[i].left_neighbor=i;
jacint@161
   115
	minimum=i;	
jacint@161
   116
	blank=false;
jacint@161
   117
      }
jacint@161
   118
      container[i].prio=value;
jacint@161
   119
    }
jacint@159
   120
    
jacint@159
   121
jacint@159
   122
jacint@159
   123
    Item top() const {
jacint@159
   124
      if ( !blank ) { 
jacint@159
   125
	return container[minimum].name;
jacint@159
   126
      } else {
jacint@159
   127
	return Item();
jacint@159
   128
      }
jacint@159
   129
    }
jacint@159
   130
    
jacint@159
   131
    
jacint@159
   132
    PrioType prio() const {
jacint@159
   133
      if ( !blank ) { 
jacint@159
   134
	return container[minimum].prio;
jacint@159
   135
      } else {
jacint@159
   136
	return PrioType();
jacint@159
   137
      }
jacint@159
   138
    }
jacint@159
   139
    
jacint@159
   140
jacint@159
   141
    const PrioType get(const Item& it) const
jacint@159
   142
    {
jacint@159
   143
      int i=iimap.get(it);
jacint@159
   144
      
jacint@159
   145
      if ( i >= 0 && container[i].in ) { 
jacint@159
   146
	return container[i].prio;
jacint@159
   147
      } else {
jacint@159
   148
	return PrioType();
jacint@159
   149
      }
jacint@159
   150
    }
jacint@159
   151
jacint@159
   152
jacint@159
   153
    void pop() {
jacint@159
   154
      if ( !blank ) {
jacint@159
   155
	
jacint@159
   156
	/*The first case is that there are only one root.*/
jacint@159
   157
	if ( container[minimum].left_neighbor==minimum ) {
jacint@159
   158
	  container[minimum].in=false;
jacint@159
   159
	  if ( container[minimum].degree==0 ) blank=true; 
jacint@159
   160
	  else { 
jacint@159
   161
	    makeroot(container[minimum].child);
jacint@159
   162
	    minimum=container[minimum].child;
jacint@159
   163
	    balance();
jacint@159
   164
	  } 
jacint@159
   165
       } else {
jacint@159
   166
	 int right=container[minimum].right_neighbor;
jacint@159
   167
	 unlace(minimum);
jacint@159
   168
	 container[minimum].in=false;
jacint@159
   169
	 if ( container[minimum].degree > 0 ) {
jacint@159
   170
	   int left=container[minimum].left_neighbor;
jacint@159
   171
	   int child=container[minimum].child;
jacint@159
   172
	   int last_child=container[child].left_neighbor;
jacint@159
   173
	   
jacint@159
   174
	   container[left].right_neighbor=child;
jacint@159
   175
	   container[child].left_neighbor=left;
jacint@159
   176
	   container[right].left_neighbor=last_child;
jacint@159
   177
	   container[last_child].right_neighbor=right;
jacint@159
   178
	   
jacint@159
   179
	   makeroot(child);
jacint@159
   180
	 }
jacint@159
   181
	 minimum=right;
jacint@159
   182
	 balance();
jacint@159
   183
       } // the case where there are more roots
jacint@159
   184
     } 
jacint@159
   185
   }
jacint@159
   186
jacint@159
   187
    
jacint@159
   188
   void erase (const Item& it) {
jacint@159
   189
     int i=iimap.get(it);
jacint@159
   190
     
jacint@159
   191
     if ( i >= 0 && container[i].in ) { 
jacint@159
   192
	
jacint@159
   193
       if ( container[i].parent!=-1 ) {
jacint@159
   194
	 int p=container[i].parent;
jacint@159
   195
	 cut(i,p);	    
jacint@159
   196
	 cascade(p);
jacint@159
   197
	 minimum=i;     //As if its prio would be -infinity
jacint@159
   198
       }
jacint@159
   199
       pop();
jacint@159
   200
     }
jacint@159
   201
   }
jacint@159
   202
    
jacint@159
   203
jacint@161
   204
    void decrease (Item it, PrioType const value) {
jacint@161
   205
      int i=iimap.get(it);
jacint@161
   206
      container[i].prio=value;
jacint@161
   207
      int p=container[i].parent;
jacint@161
   208
 
jacint@161
   209
      if ( p!=-1 && comp(value, container[p].prio) ) {
jacint@161
   210
	cut(i,p);	    
jacint@161
   211
	cascade(p);
jacint@161
   212
	if ( comp(value, container[minimum].prio) ) minimum=i; 
jacint@161
   213
      }
jacint@161
   214
    }
jacint@159
   215
   
jacint@159
   216
jacint@159
   217
    void increase (Item it, PrioType const value) {
jacint@161
   218
      erase(it);
jacint@161
   219
      push(it, value);
jacint@159
   220
    }
jacint@159
   221
jacint@159
   222
jacint@159
   223
  private:
jacint@159
   224
    
jacint@159
   225
    void balance() {      
jacint@159
   226
    int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
jacint@159
   227
  
jacint@159
   228
    std::vector<int> A(maxdeg,-1); 
jacint@159
   229
    
jacint@159
   230
    /*
jacint@159
   231
     *Recall that now minimum does not point to the minimum prio element.
jacint@159
   232
     *We set minimum to this during balance().
jacint@159
   233
     */
jacint@159
   234
    int anchor=container[minimum].left_neighbor; 
jacint@159
   235
    int next=minimum; 
jacint@159
   236
    bool end=false; 
jacint@159
   237
    	
jacint@159
   238
       do {
jacint@159
   239
	int active=next;
jacint@159
   240
	int d=container[active].degree;
jacint@159
   241
	if ( anchor==active ) end=true;
jacint@159
   242
	next = container[active].right_neighbor;
jacint@159
   243
	if ( !comp(container[minimum].prio, container[active].prio) )
jacint@159
   244
	  minimum=active;
jacint@159
   245
jacint@159
   246
	while (A[d]!=-1) {
jacint@159
   247
	  
jacint@159
   248
	  if( comp(container[active].prio, container[A[d]].prio) ) {
jacint@159
   249
	    fuse(active,A[d]); 
jacint@159
   250
	  } else { 
jacint@159
   251
	    fuse(A[d],active);
jacint@159
   252
	    active=A[d];
jacint@159
   253
	  } 
jacint@159
   254
	  A[d]=-1;
jacint@159
   255
	  ++d;
jacint@159
   256
	}
jacint@159
   257
	
jacint@159
   258
	A[d]=active;
jacint@159
   259
       } while ( !end );
jacint@159
   260
  }
jacint@159
   261
jacint@159
   262
jacint@159
   263
jacint@159
   264
jacint@159
   265
    /*
jacint@159
   266
     *All the siblings of a are made roots.
jacint@159
   267
     */
jacint@159
   268
    void makeroot (int c)  
jacint@159
   269
    {
jacint@159
   270
      int s=c;
jacint@159
   271
      do {  
jacint@159
   272
	container[s].parent=-1;
jacint@159
   273
	s=container[s].right_neighbor;
jacint@159
   274
      } while ( s != c );
jacint@159
   275
    }
jacint@159
   276
    
jacint@159
   277
jacint@159
   278
    void cut (int a, int b) 
jacint@159
   279
    {    
jacint@159
   280
jacint@159
   281
      /*
jacint@159
   282
       *Replacing a from the children of b.
jacint@159
   283
       */
jacint@159
   284
      --container[b].degree;
jacint@159
   285
jacint@159
   286
      if ( container[b].degree !=0 ) {
jacint@159
   287
      int child=container[b].child;
jacint@159
   288
      if ( child==a ) 
jacint@159
   289
	container[b].child=container[child].right_neighbor;
jacint@159
   290
      
jacint@159
   291
      unlace(a);
jacint@159
   292
	
jacint@159
   293
      }
jacint@159
   294
    
jacint@159
   295
jacint@159
   296
      /*Lacing i to the roots.*/
jacint@159
   297
      int right=container[minimum].right_neighbor;
jacint@159
   298
      container[minimum].right_neighbor=a;
jacint@159
   299
      container[a].left_neighbor=minimum;
jacint@159
   300
      container[a].right_neighbor=right;
jacint@159
   301
      container[right].left_neighbor=a;
jacint@159
   302
jacint@159
   303
      container[a].parent=-1;
jacint@159
   304
      container[a].marked=false;
jacint@159
   305
    }
jacint@159
   306
jacint@159
   307
jacint@159
   308
    void cascade (int a) 
jacint@159
   309
    {
jacint@159
   310
      if ( container[a].parent!=-1 ) {
jacint@159
   311
	int p=container[a].parent;
jacint@159
   312
	
jacint@159
   313
	if ( container[a].marked==false ) container[a].marked=true;
jacint@159
   314
	else {
jacint@159
   315
	  cut(a,p);
jacint@159
   316
	  cascade(p);
jacint@159
   317
	}
jacint@159
   318
      }
jacint@159
   319
    }
jacint@159
   320
jacint@159
   321
jacint@159
   322
    void fuse (int a, int b) 
jacint@159
   323
    {
jacint@159
   324
      
jacint@159
   325
      unlace(b);
jacint@159
   326
jacint@159
   327
      
jacint@159
   328
      /*Lacing b under a.*/
jacint@159
   329
      container[b].parent=a;
jacint@159
   330
jacint@159
   331
      if (container[a].degree==0) {
jacint@159
   332
	container[b].left_neighbor=b;
jacint@159
   333
	container[b].right_neighbor=b;
jacint@159
   334
	container[a].child=b;	
jacint@159
   335
      } else {
jacint@159
   336
	int child=container[a].child;
jacint@159
   337
	int last_child=container[child].left_neighbor;
jacint@159
   338
	container[child].left_neighbor=b;
jacint@159
   339
	container[b].right_neighbor=child;
jacint@159
   340
	container[last_child].right_neighbor=b;
jacint@159
   341
	container[b].left_neighbor=last_child;
jacint@159
   342
      }
jacint@159
   343
jacint@159
   344
      ++container[a].degree;
jacint@159
   345
      
jacint@159
   346
      container[b].marked=false;
jacint@159
   347
    }
jacint@159
   348
jacint@159
   349
jacint@159
   350
    /*
jacint@159
   351
     *It is invoked only if a has siblings.
jacint@159
   352
     */
jacint@159
   353
jacint@159
   354
    void unlace (int a) {      
jacint@159
   355
      int leftn=container[a].left_neighbor;
jacint@159
   356
      int rightn=container[a].right_neighbor;
jacint@159
   357
      container[leftn].right_neighbor=rightn;
jacint@159
   358
      container[rightn].left_neighbor=leftn;
jacint@159
   359
    }
jacint@159
   360
jacint@159
   361
jacint@159
   362
    class store {
jacint@159
   363
      friend class FibHeap;
jacint@159
   364
      
jacint@159
   365
      Item name;
jacint@159
   366
      int parent;
jacint@159
   367
      int left_neighbor;
jacint@159
   368
      int right_neighbor;
jacint@159
   369
      int child;
jacint@159
   370
      int degree;  
jacint@159
   371
      bool marked;
jacint@159
   372
      bool in;
jacint@159
   373
      PrioType prio;
jacint@159
   374
jacint@159
   375
      store() : parent(-1), child(-1), degree(), marked(false), in(true) {} 
jacint@159
   376
    };
jacint@159
   377
    
jacint@159
   378
  };
jacint@159
   379
  
jacint@159
   380
} //namespace hugo
jacint@159
   381
#endif 
jacint@159
   382
jacint@159
   383
jacint@159
   384
jacint@159
   385
jacint@159
   386
jacint@159
   387