lemon/fib_heap.h
author hegyi
Mon, 21 Nov 2005 18:03:20 +0000
changeset 1823 cb082cdf3667
parent 1717 75fe24093ded
child 1834 0a14e1ae45a1
permissions -rw-r--r--
NewMapWin has become Dialog instead of Window. Therefore it is created dynamically, when there is need for it, instead of keeping one instance in memory. This solution is slower, but more correct than before.
     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       if (num_items != 0) {
   121 	for (int i = 0; i < (int)container.size(); ++i) {
   122 	  iimap[container[i].name] = -2;
   123 	}
   124       }
   125       container.clear(); minimum = 0; num_items = 0;
   126     }
   127 
   128     /// \brief \c item gets to the heap with priority \c value independently 
   129     /// if \c item was already there.
   130     ///
   131     /// This method calls \ref push(\c item, \c value) if \c item is not
   132     /// stored in the heap and it calls \ref decrease(\c item, \c value) or
   133     /// \ref increase(\c item, \c value) otherwise.
   134     void set (Item const item, PrioType const value); 
   135     
   136     /// \brief Adds \c item to the heap with priority \c value. 
   137     ///    
   138     /// Adds \c item to the heap with priority \c value. 
   139     /// \pre \c item must not be stored in the heap. 
   140     void push (Item const item, PrioType const value);
   141     
   142     /// \brief Returns the item with minimum priority relative to \c Compare.
   143     ///
   144     /// This method returns the item with minimum priority relative to \c
   145     /// Compare.  
   146     /// \pre The heap must be nonempty.  
   147     Item top() const { return container[minimum].name; }
   148 
   149     /// \brief Returns the minimum priority relative to \c Compare.
   150     ///
   151     /// It returns the minimum priority relative to \c Compare.
   152     /// \pre The heap must be nonempty.
   153     PrioType prio() const { return container[minimum].prio; }
   154     
   155     /// \brief Returns the priority of \c item.
   156     ///
   157     /// This function returns the priority of \c item.
   158     /// \pre \c item must be in the heap.
   159     PrioType& operator[](const Item& item) { 
   160       return container[iimap[item]].prio; 
   161     }
   162     
   163     /// \brief Returns the priority of \c item.
   164     ///
   165     /// It returns the priority of \c item.
   166     /// \pre \c item must be in the heap.
   167     const PrioType& operator[](const Item& item) const { 
   168       return container[iimap[item]].prio; 
   169     }
   170 
   171 
   172     /// \brief Deletes the item with minimum priority relative to \c Compare.
   173     ///
   174     /// This method deletes the item with minimum priority relative to \c
   175     /// Compare from the heap.  
   176     /// \pre The heap must be non-empty.  
   177     void pop();
   178 
   179     /// \brief Deletes \c item from the heap.
   180     ///
   181     /// This method deletes \c item from the heap, if \c item was already
   182     /// stored in the heap. It is quite inefficient in Fibonacci heaps.
   183     void erase (const Item& item); 
   184 
   185     /// \brief Decreases the priority of \c item to \c value.
   186     ///
   187     /// This method decreases the priority of \c item to \c value.
   188     /// \pre \c item must be stored in the heap with priority at least \c
   189     ///   value relative to \c Compare.
   190     void decrease (Item item, PrioType const value); 
   191 
   192     /// \brief Increases the priority of \c item to \c value.
   193     ///
   194     /// This method sets the priority of \c item to \c value. Though
   195     /// there is no precondition on the priority of \c item, this
   196     /// method should be used only if it is indeed necessary to increase
   197     /// (relative to \c Compare) the priority of \c item, because this
   198     /// method is inefficient.
   199     void increase (Item item, PrioType const value) {
   200       erase(item);
   201       push(item, value);
   202     }
   203 
   204 
   205     /// \brief Returns if \c item is in, has already been in, or has never 
   206     /// been in the heap.
   207     ///
   208     /// This method returns PRE_HEAP if \c item has never been in the
   209     /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
   210     /// otherwise. In the latter case it is possible that \c item will
   211     /// get back to the heap again.
   212     state_enum state(const Item &item) const {
   213       int i=iimap[item];
   214       if( i>=0 ) {
   215 	if ( container[i].in ) i=0;
   216 	else i=-2; 
   217       }
   218       return state_enum(i);
   219     }    
   220     
   221   private:
   222     
   223     void balance();
   224     void makeroot(int c);
   225     void cut(int a, int b);
   226     void cascade(int a);
   227     void fuse(int a, int b);
   228     void unlace(int a);
   229 
   230 
   231     class store {
   232       friend class FibHeap;
   233       
   234       Item name;
   235       int parent;
   236       int left_neighbor;
   237       int right_neighbor;
   238       int child;
   239       int degree;  
   240       bool marked;
   241       bool in;
   242       PrioType prio;
   243       
   244       store() : parent(-1), child(-1), degree(), marked(false), in(true) {} 
   245     };
   246   };    
   247  
   248 
   249 
   250     // **********************************************************************
   251     //  IMPLEMENTATIONS
   252     // **********************************************************************
   253     
   254   template <typename Item, typename Prio, typename ItemIntMap, 
   255     typename Compare>
   256   void FibHeap<Item, Prio, ItemIntMap, Compare>::set 
   257   (Item const item, PrioType const value) 
   258   {
   259     int i=iimap[item];
   260     if ( i >= 0 && container[i].in ) {
   261       if ( comp(value, container[i].prio) ) decrease(item, value); 
   262       if ( comp(container[i].prio, value) ) increase(item, value); 
   263     } else push(item, value);
   264   }
   265     
   266   template <typename Item, typename Prio, typename ItemIntMap, 
   267     typename Compare>
   268   void FibHeap<Item, Prio, ItemIntMap, Compare>::push 
   269   (Item const item, PrioType const value) {
   270       int i=iimap[item];      
   271       if ( i < 0 ) {
   272 	int s=container.size();
   273 	iimap.set( item, s );	
   274 	store st;
   275 	st.name=item;
   276 	container.push_back(st);
   277 	i=s;
   278       } else {
   279 	container[i].parent=container[i].child=-1;
   280 	container[i].degree=0;
   281 	container[i].in=true;
   282 	container[i].marked=false;
   283       }
   284 
   285       if ( num_items ) {
   286 	container[container[minimum].right_neighbor].left_neighbor=i;
   287 	container[i].right_neighbor=container[minimum].right_neighbor;
   288 	container[minimum].right_neighbor=i;
   289 	container[i].left_neighbor=minimum;
   290 	if ( comp( value, container[minimum].prio) ) minimum=i; 
   291       } else {
   292 	container[i].right_neighbor=container[i].left_neighbor=i;
   293 	minimum=i;	
   294       }
   295       container[i].prio=value;
   296       ++num_items;
   297     }
   298     
   299   template <typename Item, typename Prio, typename ItemIntMap, 
   300     typename Compare>
   301   void FibHeap<Item, Prio, ItemIntMap, Compare>::pop() {
   302       /*The first case is that there are only one root.*/
   303       if ( container[minimum].left_neighbor==minimum ) {
   304 	container[minimum].in=false;
   305 	if ( container[minimum].degree!=0 ) { 
   306 	  makeroot(container[minimum].child);
   307 	  minimum=container[minimum].child;
   308 	  balance();
   309 	}
   310       } else {
   311 	int right=container[minimum].right_neighbor;
   312 	unlace(minimum);
   313 	container[minimum].in=false;
   314 	if ( container[minimum].degree > 0 ) {
   315 	  int left=container[minimum].left_neighbor;
   316 	  int child=container[minimum].child;
   317 	  int last_child=container[child].left_neighbor;
   318 	
   319 	  makeroot(child);
   320 	  
   321 	  container[left].right_neighbor=child;
   322 	  container[child].left_neighbor=left;
   323 	  container[right].left_neighbor=last_child;
   324 	  container[last_child].right_neighbor=right;
   325 	}
   326 	minimum=right;
   327 	balance();
   328       } // the case where there are more roots
   329       --num_items;   
   330     }
   331 
   332 
   333   template <typename Item, typename Prio, typename ItemIntMap, 
   334     typename Compare>
   335   void FibHeap<Item, Prio, ItemIntMap, Compare>::erase 
   336   (const Item& item) {
   337       int i=iimap[item];
   338       
   339       if ( i >= 0 && container[i].in ) { 	
   340 	if ( container[i].parent!=-1 ) {
   341 	  int p=container[i].parent;
   342 	  cut(i,p);	    
   343 	  cascade(p);
   344 	}
   345 	minimum=i;     //As if its prio would be -infinity
   346 	pop();
   347       }
   348   }
   349     
   350   template <typename Item, typename Prio, typename ItemIntMap, 
   351     typename Compare>
   352   void FibHeap<Item, Prio, ItemIntMap, Compare>::decrease 
   353   (Item item, PrioType const value) {
   354       int i=iimap[item];
   355       container[i].prio=value;
   356       int p=container[i].parent;
   357       
   358       if ( p!=-1 && comp(value, container[p].prio) ) {
   359 	cut(i,p);	    
   360 	cascade(p);
   361       }      
   362       if ( comp(value, container[minimum].prio) ) minimum=i; 
   363   }
   364  
   365 
   366   template <typename Item, typename Prio, typename ItemIntMap, 
   367     typename Compare>
   368   void FibHeap<Item, Prio, ItemIntMap, Compare>::balance() {      
   369 
   370     int maxdeg=int( std::floor( 2.08*log(double(container.size()))))+1;
   371   
   372     std::vector<int> A(maxdeg,-1); 
   373     
   374     /*
   375      *Recall that now minimum does not point to the minimum prio element.
   376      *We set minimum to this during balance().
   377      */
   378     int anchor=container[minimum].left_neighbor; 
   379     int next=minimum; 
   380     bool end=false; 
   381     	
   382        do {
   383 	int active=next;
   384 	if ( anchor==active ) end=true;
   385 	int d=container[active].degree;
   386 	next=container[active].right_neighbor;
   387 
   388 	while (A[d]!=-1) {	  
   389 	  if( comp(container[active].prio, container[A[d]].prio) ) {
   390 	    fuse(active,A[d]); 
   391 	  } else { 
   392 	    fuse(A[d],active);
   393 	    active=A[d];
   394 	  } 
   395 	  A[d]=-1;
   396 	  ++d;
   397 	}	
   398 	A[d]=active;
   399        } while ( !end );
   400 
   401 
   402        while ( container[minimum].parent >=0 ) minimum=container[minimum].parent;
   403        int s=minimum;
   404        int m=minimum;
   405        do {  
   406 	 if ( comp(container[s].prio, container[minimum].prio) ) minimum=s;
   407 	 s=container[s].right_neighbor;
   408        } while ( s != m );
   409     }
   410 
   411   template <typename Item, typename Prio, typename ItemIntMap, 
   412     typename Compare>
   413   void FibHeap<Item, Prio, ItemIntMap, Compare>::makeroot 
   414   (int c) {
   415       int s=c;
   416       do {  
   417 	container[s].parent=-1;
   418 	s=container[s].right_neighbor;
   419       } while ( s != c );
   420     }
   421   
   422   
   423   template <typename Item, typename Prio, typename ItemIntMap, 
   424     typename Compare>
   425   void FibHeap<Item, Prio, ItemIntMap, Compare>::cut 
   426   (int a, int b) {    
   427     /*
   428      *Replacing a from the children of b.
   429      */
   430     --container[b].degree;
   431     
   432     if ( container[b].degree !=0 ) {
   433       int child=container[b].child;
   434       if ( child==a ) 
   435 	container[b].child=container[child].right_neighbor;
   436       unlace(a);
   437     }
   438     
   439     
   440     /*Lacing a to the roots.*/
   441     int right=container[minimum].right_neighbor;
   442     container[minimum].right_neighbor=a;
   443     container[a].left_neighbor=minimum;
   444     container[a].right_neighbor=right;
   445     container[right].left_neighbor=a;
   446     
   447     container[a].parent=-1;
   448     container[a].marked=false;
   449   }
   450   
   451 
   452   template <typename Item, typename Prio, typename ItemIntMap, 
   453     typename Compare>
   454   void FibHeap<Item, Prio, ItemIntMap, Compare>::cascade 
   455   (int a) 
   456     {
   457       if ( container[a].parent!=-1 ) {
   458 	int p=container[a].parent;
   459 	
   460 	if ( container[a].marked==false ) container[a].marked=true;
   461 	else {
   462 	  cut(a,p);
   463 	  cascade(p);
   464 	}
   465       }
   466     }
   467 
   468 
   469   template <typename Item, typename Prio, typename ItemIntMap, 
   470     typename Compare>
   471   void FibHeap<Item, Prio, ItemIntMap, Compare>::fuse 
   472   (int a, int b) {
   473       unlace(b);
   474       
   475       /*Lacing b under a.*/
   476       container[b].parent=a;
   477 
   478       if (container[a].degree==0) {
   479 	container[b].left_neighbor=b;
   480 	container[b].right_neighbor=b;
   481 	container[a].child=b;	
   482       } else {
   483 	int child=container[a].child;
   484 	int last_child=container[child].left_neighbor;
   485 	container[child].left_neighbor=b;
   486 	container[b].right_neighbor=child;
   487 	container[last_child].right_neighbor=b;
   488 	container[b].left_neighbor=last_child;
   489       }
   490 
   491       ++container[a].degree;
   492       
   493       container[b].marked=false;
   494     }
   495 
   496   
   497   /*
   498    *It is invoked only if a has siblings.
   499    */
   500   template <typename Item, typename Prio, typename ItemIntMap, 
   501     typename Compare>
   502   void FibHeap<Item, Prio, ItemIntMap, Compare>::unlace 
   503   (int a) {      
   504       int leftn=container[a].left_neighbor;
   505       int rightn=container[a].right_neighbor;
   506       container[leftn].right_neighbor=rightn;
   507       container[rightn].left_neighbor=leftn;
   508   }
   509   
   510   ///@}
   511 
   512 } //namespace lemon
   513 
   514 #endif //LEMON_FIB_HEAP_H
   515