src/hugo/fib_heap.h
author deba
Wed, 08 Sep 2004 12:06:45 +0000
changeset 822 88226d9fe821
parent 491 4804c967543d
child 857 4e948fd205f7
permissions -rw-r--r--
The MapFactories have been removed from the code because
if we use macros then they increases only the complexity.

The pair iterators of the maps are separeted from the maps.

Some macros and comments has been changed.
alpar@255
     1
// -*- C++ -*-
alpar@255
     2
jacint@373
     3
#ifndef HUGO_FIB_HEAP_H
jacint@373
     4
#define HUGO_FIB_HEAP_H
alpar@255
     5
klao@491
     6
///\ingroup auxdat
alpar@255
     7
///\file
alpar@255
     8
///\brief Fibonacci Heap implementation.
alpar@255
     9
alpar@255
    10
#include <vector>
alpar@255
    11
#include <functional>
alpar@255
    12
#include <math.h>
alpar@255
    13
alpar@255
    14
namespace hugo {
alpar@255
    15
  
alpar@430
    16
  /// \addtogroup auxdat
alpar@430
    17
  /// @{
alpar@430
    18
jacint@373
    19
  /// An implementation of the Fibonacci Heap.
jacint@373
    20
jacint@373
    21
  /**
jacint@387
    22
     This class implements the \e Fibonacci \e heap data structure. A \e heap
jacint@387
    23
     is a data structure for storing items with specified values called \e
jacint@387
    24
     priorities, such that finding the item with minimum priority with respect
jacint@387
    25
     to \e Compare is efficient. In a heap one can change the priority of an
jacint@387
    26
     item, add or erase an item, etc.
jacint@373
    27
jacint@387
    28
     The methods \ref increase and \ref erase are not efficient in a Fibonacci
jacint@387
    29
     heap. In case of many calls to these operations, it is better to use a
jacint@387
    30
     \e binary \e heap.
jacint@373
    31
     
jacint@387
    32
     \param Item The type of the items to be stored.  
jacint@387
    33
     \param Prio The type of the priority of the items.
jacint@387
    34
     \param ItemIntMap A read and writable Item int map, for the usage of
jacint@373
    35
     the heap.
jacint@387
    36
     \param Compare A class for the comparison of the priorities. The
jacint@373
    37
     default is \c std::less<Prio>.
jacint@373
    38
jacint@373
    39
  */
jacint@373
    40
jacint@373
    41
#ifdef DOXYGEN
jacint@373
    42
  template <typename Item, 
jacint@373
    43
	    typename Prio, 
jacint@373
    44
	    typename ItemIntMap, 
jacint@373
    45
	    typename Compare>
jacint@373
    46
#else
jacint@373
    47
  template <typename Item, 
jacint@373
    48
	    typename Prio, 
jacint@373
    49
	    typename ItemIntMap, 
alpar@255
    50
	    typename Compare = std::less<Prio> >
jacint@373
    51
#endif
alpar@255
    52
  class FibHeap {
jacint@387
    53
  public:     
alpar@255
    54
    typedef Prio PrioType;
alpar@255
    55
    
jacint@373
    56
  private:
alpar@255
    57
    class store;
alpar@255
    58
    
alpar@255
    59
    std::vector<store> container;
alpar@255
    60
    int minimum;
alpar@255
    61
    ItemIntMap &iimap;
alpar@255
    62
    Compare comp;
alpar@255
    63
    int num_items;
jacint@373
    64
    
alpar@255
    65
  public:
alpar@255
    66
    enum state_enum {
alpar@255
    67
      IN_HEAP = 0,
alpar@255
    68
      PRE_HEAP = -1,
alpar@255
    69
      POST_HEAP = -2
alpar@255
    70
    };
alpar@255
    71
    
jacint@373
    72
    FibHeap(ItemIntMap &_iimap) : minimum(0), iimap(_iimap), num_items() {} 
jacint@373
    73
    FibHeap(ItemIntMap &_iimap, const Compare &_comp) : minimum(0), 
alpar@255
    74
      iimap(_iimap), comp(_comp), num_items() {}
alpar@255
    75
    
jacint@373
    76
    ///The number of items stored in the heap.
jacint@373
    77
jacint@373
    78
    /**
jacint@387
    79
       Returns the number of items stored in the heap.
jacint@373
    80
    */
jacint@373
    81
    int size() const { return num_items; }
jacint@373
    82
jacint@373
    83
    ///Checks if the heap stores no items.
alpar@255
    84
    
jacint@373
    85
    /**
jacint@387
    86
       Returns \c true iff the heap stores no items.
jacint@373
    87
    */
jacint@373
    88
    bool empty() const { return num_items==0; }
jacint@373
    89
jacint@387
    90
    ///\c item gets to the heap with priority \c value independently if \c item was already there.
jacint@373
    91
jacint@373
    92
    /**
jacint@387
    93
       This method calls \ref push(\c item, \c value) if \c item is not
jacint@387
    94
       stored in the heap and it calls \ref decrease(\c item, \c value) or
jacint@387
    95
       \ref increase(\c item, \c value) otherwise.
jacint@373
    96
    */
jacint@387
    97
    void set (Item const item, PrioType const value); 
jacint@373
    98
    
jacint@373
    99
    ///Adds \c item to the heap with priority \c value. 
jacint@373
   100
    
jacint@373
   101
    /**
jacint@373
   102
       Adds \c item to the heap with priority \c value. 
jacint@373
   103
       \pre \c item must not be stored in the heap. 
jacint@373
   104
    */
jacint@387
   105
    void push (Item const item, PrioType const value);
jacint@373
   106
    
jacint@373
   107
    
jacint@373
   108
    ///Returns the item having the minimum priority w.r.t.  Compare.
jacint@373
   109
    
jacint@373
   110
    /**
jacint@373
   111
       This method returns the item having the minimum priority w.r.t.  Compare. 
jacint@373
   112
       \pre The heap must be nonempty.
jacint@373
   113
    */
jacint@373
   114
    Item top() const { return container[minimum].name; }
jacint@373
   115
    
jacint@373
   116
jacint@373
   117
    ///Returns the minimum priority w.r.t.  Compare.
jacint@373
   118
jacint@373
   119
    /**
jacint@373
   120
       It returns the minimum priority w.r.t.  Compare.
jacint@373
   121
       \pre The heap must be nonempty.
jacint@373
   122
    */
jacint@373
   123
    PrioType prio() const { return container[minimum].prio; }
jacint@373
   124
    
jacint@373
   125
jacint@373
   126
    ///Returns the priority of \c item.
jacint@373
   127
jacint@373
   128
    /**
jacint@373
   129
       It returns the priority of \c item.
jacint@373
   130
       \pre \c item must be in the heap.
jacint@373
   131
    */
jacint@387
   132
    PrioType& operator[](const Item& item) { 
jacint@387
   133
      return container[iimap[item]].prio; 
jacint@387
   134
    }
jacint@373
   135
    
jacint@373
   136
    ///Returns the priority of \c item.
jacint@373
   137
    
jacint@373
   138
    /**
jacint@373
   139
       It returns the priority of \c item.
jacint@373
   140
       \pre \c item must be in the heap.
jacint@373
   141
    */
jacint@387
   142
    const PrioType& operator[](const Item& item) const { 
jacint@387
   143
      return container[iimap[item]].prio; 
alpar@255
   144
    }
alpar@255
   145
alpar@255
   146
jacint@373
   147
    ///Deletes the item with minimum priority w.r.t.  Compare.
alpar@255
   148
jacint@373
   149
    /**
jacint@373
   150
    This method deletes the item with minimum priority w.r.t. 
jacint@373
   151
    Compare from the heap.
jacint@373
   152
    \pre The heap must be non-empty.
jacint@373
   153
    */
jacint@373
   154
    void pop();
jacint@373
   155
jacint@373
   156
    ///Deletes \c item from the heap.
jacint@373
   157
jacint@373
   158
    /**
jacint@373
   159
       This method deletes \c item from the heap, if \c item was already
jacint@373
   160
       stored in the heap. It is quite inefficient in Fibonacci heaps.
jacint@373
   161
    */
jacint@387
   162
    void erase (const Item& item); 
jacint@373
   163
jacint@373
   164
    ///Decreases the priority of \c item to \c value.
jacint@373
   165
jacint@373
   166
    /**
jacint@373
   167
       This method decreases the priority of \c item to \c value.
jacint@373
   168
       \pre \c item must be stored in the heap with priority at least \c
jacint@373
   169
       value w.r.t.  Compare.
jacint@373
   170
    */
jacint@387
   171
    void decrease (Item item, PrioType const value); 
jacint@373
   172
jacint@373
   173
jacint@373
   174
    ///Increases the priority of \c item to \c value.
jacint@373
   175
jacint@373
   176
    /**
jacint@373
   177
       This method sets the priority of \c item to \c value. Though
jacint@373
   178
       there is no precondition on the priority of \c item, this
jacint@387
   179
       method should be used only if there is a need to really \e increase
jacint@373
   180
       (w.r.t.  Compare) the priority of \c item, because this
jacint@373
   181
       method is inefficient.
jacint@373
   182
    */
jacint@387
   183
    void increase (Item item, PrioType const value) {
jacint@387
   184
      erase(item);
jacint@387
   185
      push(item, value);
jacint@373
   186
    }
jacint@373
   187
jacint@373
   188
jacint@387
   189
    ///Tells if \c item is in, was already in, or has never been in the heap.
jacint@373
   190
jacint@373
   191
    /**
jacint@373
   192
       This method returns PRE_HEAP if \c item has never been in the
jacint@373
   193
       heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
jacint@373
   194
       otherwise. In the latter case it is possible that \c item will
jacint@373
   195
       get back to the heap again.
jacint@373
   196
    */
jacint@387
   197
    state_enum state(const Item &item) const {
jacint@387
   198
      int i=iimap[item];
jacint@387
   199
      if( i>=0 ) {
jacint@387
   200
	if ( container[i].in ) i=0;
jacint@387
   201
	else i=-2; 
jacint@387
   202
      }
jacint@387
   203
      return state_enum(i);
jacint@387
   204
    }    
jacint@387
   205
    
jacint@387
   206
  private:
jacint@387
   207
    
jacint@387
   208
    void balance();
jacint@387
   209
    void makeroot(int c);
jacint@387
   210
    void cut(int a, int b);
jacint@387
   211
    void cascade(int a);
jacint@387
   212
    void fuse(int a, int b);
jacint@387
   213
    void unlace(int a);
jacint@373
   214
jacint@373
   215
jacint@387
   216
    class store {
jacint@387
   217
      friend class FibHeap;
jacint@387
   218
      
jacint@387
   219
      Item name;
jacint@387
   220
      int parent;
jacint@387
   221
      int left_neighbor;
jacint@387
   222
      int right_neighbor;
jacint@387
   223
      int child;
jacint@387
   224
      int degree;  
jacint@387
   225
      bool marked;
jacint@387
   226
      bool in;
jacint@387
   227
      PrioType prio;
jacint@387
   228
      
jacint@387
   229
      store() : parent(-1), child(-1), degree(), marked(false), in(true) {} 
jacint@387
   230
    };
jacint@387
   231
  };    
jacint@387
   232
 
jacint@387
   233
jacint@373
   234
jacint@373
   235
    // **********************************************************************
jacint@373
   236
    //  IMPLEMENTATIONS
jacint@373
   237
    // **********************************************************************
jacint@373
   238
    
jacint@387
   239
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   240
    typename Compare>
jacint@387
   241
  void FibHeap<Item, Prio, ItemIntMap, Compare>::set 
jacint@387
   242
  (Item const item, PrioType const value) 
jacint@387
   243
  {
jacint@387
   244
    int i=iimap[item];
jacint@387
   245
    if ( i >= 0 && container[i].in ) {
jacint@387
   246
      if ( comp(value, container[i].prio) ) decrease(item, value); 
jacint@387
   247
      if ( comp(container[i].prio, value) ) increase(item, value); 
jacint@387
   248
    } else push(item, value);
jacint@387
   249
  }
alpar@255
   250
    
jacint@387
   251
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   252
    typename Compare>
jacint@387
   253
  void FibHeap<Item, Prio, ItemIntMap, Compare>::push 
jacint@387
   254
  (Item const item, PrioType const value) {
jacint@387
   255
      int i=iimap[item];      
alpar@255
   256
      if ( i < 0 ) {
alpar@255
   257
	int s=container.size();
jacint@387
   258
	iimap.set( item, s );	
alpar@255
   259
	store st;
jacint@387
   260
	st.name=item;
alpar@255
   261
	container.push_back(st);
alpar@255
   262
	i=s;
alpar@255
   263
      } else {
alpar@255
   264
	container[i].parent=container[i].child=-1;
alpar@255
   265
	container[i].degree=0;
alpar@255
   266
	container[i].in=true;
alpar@255
   267
	container[i].marked=false;
alpar@255
   268
      }
alpar@255
   269
alpar@255
   270
      if ( num_items ) {
alpar@255
   271
	container[container[minimum].right_neighbor].left_neighbor=i;
alpar@255
   272
	container[i].right_neighbor=container[minimum].right_neighbor;
alpar@255
   273
	container[minimum].right_neighbor=i;
alpar@255
   274
	container[i].left_neighbor=minimum;
alpar@255
   275
	if ( comp( value, container[minimum].prio) ) minimum=i; 
alpar@255
   276
      } else {
alpar@255
   277
	container[i].right_neighbor=container[i].left_neighbor=i;
alpar@255
   278
	minimum=i;	
alpar@255
   279
      }
alpar@255
   280
      container[i].prio=value;
alpar@255
   281
      ++num_items;
alpar@255
   282
    }
alpar@255
   283
    
jacint@387
   284
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   285
    typename Compare>
jacint@387
   286
  void FibHeap<Item, Prio, ItemIntMap, Compare>::pop() {
alpar@255
   287
      /*The first case is that there are only one root.*/
alpar@255
   288
      if ( container[minimum].left_neighbor==minimum ) {
alpar@255
   289
	container[minimum].in=false;
alpar@255
   290
	if ( container[minimum].degree!=0 ) { 
alpar@255
   291
	  makeroot(container[minimum].child);
alpar@255
   292
	  minimum=container[minimum].child;
alpar@255
   293
	  balance();
alpar@255
   294
	}
alpar@255
   295
      } else {
alpar@255
   296
	int right=container[minimum].right_neighbor;
alpar@255
   297
	unlace(minimum);
alpar@255
   298
	container[minimum].in=false;
alpar@255
   299
	if ( container[minimum].degree > 0 ) {
alpar@255
   300
	  int left=container[minimum].left_neighbor;
alpar@255
   301
	  int child=container[minimum].child;
alpar@255
   302
	  int last_child=container[child].left_neighbor;
alpar@255
   303
	
alpar@255
   304
	  makeroot(child);
alpar@255
   305
	  
alpar@255
   306
	  container[left].right_neighbor=child;
alpar@255
   307
	  container[child].left_neighbor=left;
alpar@255
   308
	  container[right].left_neighbor=last_child;
alpar@255
   309
	  container[last_child].right_neighbor=right;
alpar@255
   310
	}
alpar@255
   311
	minimum=right;
alpar@255
   312
	balance();
alpar@255
   313
      } // the case where there are more roots
alpar@255
   314
      --num_items;   
alpar@255
   315
    }
alpar@255
   316
jacint@387
   317
jacint@387
   318
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   319
    typename Compare>
jacint@387
   320
  void FibHeap<Item, Prio, ItemIntMap, Compare>::erase 
jacint@387
   321
  (const Item& item) {
jacint@387
   322
      int i=iimap[item];
alpar@255
   323
      
alpar@255
   324
      if ( i >= 0 && container[i].in ) { 	
alpar@255
   325
	if ( container[i].parent!=-1 ) {
alpar@255
   326
	  int p=container[i].parent;
alpar@255
   327
	  cut(i,p);	    
alpar@255
   328
	  cascade(p);
alpar@255
   329
	}
alpar@255
   330
	minimum=i;     //As if its prio would be -infinity
alpar@255
   331
	pop();
alpar@255
   332
      }
jacint@387
   333
  }
alpar@255
   334
    
jacint@387
   335
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   336
    typename Compare>
jacint@387
   337
  void FibHeap<Item, Prio, ItemIntMap, Compare>::decrease 
jacint@387
   338
  (Item item, PrioType const value) {
jacint@387
   339
      int i=iimap[item];
alpar@255
   340
      container[i].prio=value;
alpar@255
   341
      int p=container[i].parent;
alpar@255
   342
      
alpar@255
   343
      if ( p!=-1 && comp(value, container[p].prio) ) {
alpar@255
   344
	cut(i,p);	    
alpar@255
   345
	cascade(p);
alpar@255
   346
      }      
alpar@255
   347
      if ( comp(value, container[minimum].prio) ) minimum=i; 
jacint@387
   348
  }
jacint@387
   349
 
alpar@255
   350
jacint@387
   351
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   352
    typename Compare>
jacint@387
   353
  void FibHeap<Item, Prio, ItemIntMap, Compare>::balance() {      
alpar@255
   354
alpar@255
   355
    int maxdeg=int( floor( 2.08*log(double(container.size()))))+1;
alpar@255
   356
  
alpar@255
   357
    std::vector<int> A(maxdeg,-1); 
alpar@255
   358
    
alpar@255
   359
    /*
alpar@255
   360
     *Recall that now minimum does not point to the minimum prio element.
alpar@255
   361
     *We set minimum to this during balance().
alpar@255
   362
     */
alpar@255
   363
    int anchor=container[minimum].left_neighbor; 
alpar@255
   364
    int next=minimum; 
alpar@255
   365
    bool end=false; 
alpar@255
   366
    	
alpar@255
   367
       do {
alpar@255
   368
	int active=next;
alpar@255
   369
	if ( anchor==active ) end=true;
alpar@255
   370
	int d=container[active].degree;
alpar@255
   371
	next=container[active].right_neighbor;
alpar@255
   372
alpar@255
   373
	while (A[d]!=-1) {	  
alpar@255
   374
	  if( comp(container[active].prio, container[A[d]].prio) ) {
alpar@255
   375
	    fuse(active,A[d]); 
alpar@255
   376
	  } else { 
alpar@255
   377
	    fuse(A[d],active);
alpar@255
   378
	    active=A[d];
alpar@255
   379
	  } 
alpar@255
   380
	  A[d]=-1;
alpar@255
   381
	  ++d;
alpar@255
   382
	}	
alpar@255
   383
	A[d]=active;
alpar@255
   384
       } while ( !end );
alpar@255
   385
alpar@255
   386
alpar@255
   387
       while ( container[minimum].parent >=0 ) minimum=container[minimum].parent;
alpar@255
   388
       int s=minimum;
alpar@255
   389
       int m=minimum;
alpar@255
   390
       do {  
alpar@255
   391
	 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s;
alpar@255
   392
	 s=container[s].right_neighbor;
alpar@255
   393
       } while ( s != m );
alpar@255
   394
    }
alpar@255
   395
jacint@387
   396
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   397
    typename Compare>
jacint@387
   398
  void FibHeap<Item, Prio, ItemIntMap, Compare>::makeroot 
jacint@387
   399
  (int c) {
alpar@255
   400
      int s=c;
alpar@255
   401
      do {  
alpar@255
   402
	container[s].parent=-1;
alpar@255
   403
	s=container[s].right_neighbor;
alpar@255
   404
      } while ( s != c );
alpar@255
   405
    }
jacint@387
   406
  
jacint@387
   407
  
jacint@387
   408
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   409
    typename Compare>
jacint@387
   410
  void FibHeap<Item, Prio, ItemIntMap, Compare>::cut 
jacint@387
   411
  (int a, int b) {    
jacint@387
   412
    /*
jacint@387
   413
     *Replacing a from the children of b.
jacint@387
   414
     */
jacint@387
   415
    --container[b].degree;
alpar@255
   416
    
jacint@387
   417
    if ( container[b].degree !=0 ) {
jacint@387
   418
      int child=container[b].child;
jacint@387
   419
      if ( child==a ) 
jacint@387
   420
	container[b].child=container[child].right_neighbor;
jacint@387
   421
      unlace(a);
jacint@387
   422
    }
jacint@387
   423
    
jacint@387
   424
    
jacint@387
   425
    /*Lacing a to the roots.*/
jacint@387
   426
    int right=container[minimum].right_neighbor;
jacint@387
   427
    container[minimum].right_neighbor=a;
jacint@387
   428
    container[a].left_neighbor=minimum;
jacint@387
   429
    container[a].right_neighbor=right;
jacint@387
   430
    container[right].left_neighbor=a;
jacint@387
   431
    
jacint@387
   432
    container[a].parent=-1;
jacint@387
   433
    container[a].marked=false;
jacint@387
   434
  }
jacint@387
   435
  
alpar@255
   436
jacint@387
   437
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   438
    typename Compare>
jacint@387
   439
  void FibHeap<Item, Prio, ItemIntMap, Compare>::cascade 
jacint@387
   440
  (int a) 
alpar@255
   441
    {
alpar@255
   442
      if ( container[a].parent!=-1 ) {
alpar@255
   443
	int p=container[a].parent;
alpar@255
   444
	
alpar@255
   445
	if ( container[a].marked==false ) container[a].marked=true;
alpar@255
   446
	else {
alpar@255
   447
	  cut(a,p);
alpar@255
   448
	  cascade(p);
alpar@255
   449
	}
alpar@255
   450
      }
alpar@255
   451
    }
alpar@255
   452
alpar@255
   453
jacint@387
   454
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   455
    typename Compare>
jacint@387
   456
  void FibHeap<Item, Prio, ItemIntMap, Compare>::fuse 
jacint@387
   457
  (int a, int b) {
alpar@255
   458
      unlace(b);
alpar@255
   459
      
alpar@255
   460
      /*Lacing b under a.*/
alpar@255
   461
      container[b].parent=a;
alpar@255
   462
alpar@255
   463
      if (container[a].degree==0) {
alpar@255
   464
	container[b].left_neighbor=b;
alpar@255
   465
	container[b].right_neighbor=b;
alpar@255
   466
	container[a].child=b;	
alpar@255
   467
      } else {
alpar@255
   468
	int child=container[a].child;
alpar@255
   469
	int last_child=container[child].left_neighbor;
alpar@255
   470
	container[child].left_neighbor=b;
alpar@255
   471
	container[b].right_neighbor=child;
alpar@255
   472
	container[last_child].right_neighbor=b;
alpar@255
   473
	container[b].left_neighbor=last_child;
alpar@255
   474
      }
alpar@255
   475
alpar@255
   476
      ++container[a].degree;
alpar@255
   477
      
alpar@255
   478
      container[b].marked=false;
alpar@255
   479
    }
alpar@255
   480
jacint@387
   481
  
jacint@387
   482
  /*
jacint@387
   483
   *It is invoked only if a has siblings.
jacint@387
   484
   */
jacint@387
   485
  template <typename Item, typename Prio, typename ItemIntMap, 
jacint@387
   486
    typename Compare>
jacint@387
   487
  void FibHeap<Item, Prio, ItemIntMap, Compare>::unlace 
jacint@387
   488
  (int a) {      
alpar@255
   489
      int leftn=container[a].left_neighbor;
alpar@255
   490
      int rightn=container[a].right_neighbor;
alpar@255
   491
      container[leftn].right_neighbor=rightn;
alpar@255
   492
      container[rightn].left_neighbor=leftn;
jacint@387
   493
  }
alpar@255
   494
  
alpar@430
   495
  ///@}
alpar@430
   496
alpar@255
   497
} //namespace hugo
alpar@477
   498
alpar@477
   499
#endif //HUGO_FIB_HEAP_H
alpar@477
   500