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