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