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