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