lemon/dheap.h
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 706 9314d9339475
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
     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_DHEAP_H
    20 #define LEMON_DHEAP_H
    21 
    22 ///\ingroup heaps
    23 ///\file
    24 ///\brief D-ary heap implementation.
    25 
    26 #include <vector>
    27 #include <utility>
    28 #include <functional>
    29 
    30 namespace lemon {
    31 
    32   /// \ingroup heaps
    33   ///
    34   ///\brief D-ary heap data structure.
    35   ///
    36   /// This class implements the \e D-ary \e heap data structure.
    37   /// It fully conforms to the \ref concepts::Heap "heap concept".
    38   ///
    39   /// The \ref DHeap "D-ary heap" is a generalization of the
    40   /// \ref BinHeap "binary heap" structure, its nodes have at most
    41   /// \c D children, instead of two.
    42   /// \ref BinHeap and \ref QuadHeap are specialized implementations
    43   /// of this structure for <tt>D=2</tt> and <tt>D=4</tt>, respectively.
    44   ///
    45   /// \tparam PR Type of the priorities of the items.
    46   /// \tparam IM A read-writable item map with \c int values, used
    47   /// internally to handle the cross references.
    48   /// \tparam D The degree of the heap, each node have at most \e D
    49   /// children. The default is 16. Powers of two are suggested to use
    50   /// so that the multiplications and divisions needed to traverse the
    51   /// nodes of the heap could be performed faster.
    52   /// \tparam CMP A functor class for comparing the priorities.
    53   /// The default is \c std::less<PR>.
    54   ///
    55   ///\sa BinHeap
    56   ///\sa FouraryHeap
    57 #ifdef DOXYGEN
    58   template <typename PR, typename IM, int D, typename CMP>
    59 #else
    60   template <typename PR, typename IM, int D = 16,
    61             typename CMP = std::less<PR> >
    62 #endif
    63   class DHeap {
    64   public:
    65     /// Type of the item-int map.
    66     typedef IM ItemIntMap;
    67     /// Type of the priorities.
    68     typedef PR Prio;
    69     /// Type of the items stored in the heap.
    70     typedef typename ItemIntMap::Key Item;
    71     /// Type of the item-priority pairs.
    72     typedef std::pair<Item,Prio> Pair;
    73     /// Functor type for comparing the priorities.
    74     typedef CMP Compare;
    75 
    76     /// \brief Type to represent the states of the items.
    77     ///
    78     /// Each item has a state associated to it. It can be "in heap",
    79     /// "pre-heap" or "post-heap". The latter two are indifferent from the
    80     /// heap's point of view, but may be useful to the user.
    81     ///
    82     /// The item-int map must be initialized in such way that it assigns
    83     /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
    84     enum State {
    85       IN_HEAP = 0,    ///< = 0.
    86       PRE_HEAP = -1,  ///< = -1.
    87       POST_HEAP = -2  ///< = -2.
    88     };
    89 
    90   private:
    91     std::vector<Pair> _data;
    92     Compare _comp;
    93     ItemIntMap &_iim;
    94 
    95   public:
    96     /// \brief Constructor.
    97     ///
    98     /// Constructor.
    99     /// \param map A map that assigns \c int values to the items.
   100     /// It is used internally to handle the cross references.
   101     /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
   102     explicit DHeap(ItemIntMap &map) : _iim(map) {}
   103 
   104     /// \brief Constructor.
   105     ///
   106     /// Constructor.
   107     /// \param map A map that assigns \c int values to the items.
   108     /// It is used internally to handle the cross references.
   109     /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
   110     /// \param comp The function object used for comparing the priorities.
   111     DHeap(ItemIntMap &map, const Compare &comp)
   112       : _iim(map), _comp(comp) {}
   113 
   114     /// \brief The number of items stored in the heap.
   115     ///
   116     /// This function returns the number of items stored in the heap.
   117     int size() const { return _data.size(); }
   118 
   119     /// \brief Check if the heap is empty.
   120     ///
   121     /// This function returns \c true if the heap is empty.
   122     bool empty() const { return _data.empty(); }
   123 
   124     /// \brief Make the heap empty.
   125     ///
   126     /// This functon makes the heap empty.
   127     /// It does not change the cross reference map. If you want to reuse
   128     /// a heap that is not surely empty, you should first clear it and
   129     /// then you should set the cross reference map to \c PRE_HEAP
   130     /// for each item.
   131     void clear() { _data.clear(); }
   132 
   133   private:
   134     int parent(int i) { return (i-1)/D; }
   135     int firstChild(int i) { return D*i+1; }
   136 
   137     bool less(const Pair &p1, const Pair &p2) const {
   138       return _comp(p1.second, p2.second);
   139     }
   140 
   141     void bubbleUp(int hole, Pair p) {
   142       int par = parent(hole);
   143       while( hole>0 && less(p,_data[par]) ) {
   144         move(_data[par],hole);
   145         hole = par;
   146         par = parent(hole);
   147       }
   148       move(p, hole);
   149     }
   150 
   151     void bubbleDown(int hole, Pair p, int length) {
   152       if( length>1 ) {
   153         int child = firstChild(hole);
   154         while( child+D<=length ) {
   155           int min=child;
   156           for (int i=1; i<D; ++i) {
   157             if( less(_data[child+i], _data[min]) )
   158               min=child+i;
   159           }
   160           if( !less(_data[min], p) )
   161             goto ok;
   162           move(_data[min], hole);
   163           hole = min;
   164           child = firstChild(hole);
   165         }
   166         if ( child<length ) {
   167           int min = child;
   168           while (++child < length) {
   169             if( less(_data[child], _data[min]) )
   170               min=child;
   171           }
   172           if( less(_data[min], p) ) {
   173             move(_data[min], hole);
   174             hole = min;
   175           }
   176         }
   177       }
   178     ok:
   179       move(p, hole);
   180     }
   181 
   182     void move(const Pair &p, int i) {
   183       _data[i] = p;
   184       _iim.set(p.first, i);
   185     }
   186 
   187   public:
   188     /// \brief Insert a pair of item and priority into the heap.
   189     ///
   190     /// This function inserts \c p.first to the heap with priority
   191     /// \c p.second.
   192     /// \param p The pair to insert.
   193     /// \pre \c p.first must not be stored in the heap.
   194     void push(const Pair &p) {
   195       int n = _data.size();
   196       _data.resize(n+1);
   197       bubbleUp(n, p);
   198     }
   199 
   200     /// \brief Insert an item into the heap with the given priority.
   201     ///
   202     /// This function inserts the given item into the heap with the
   203     /// given priority.
   204     /// \param i The item to insert.
   205     /// \param p The priority of the item.
   206     /// \pre \e i must not be stored in the heap.
   207     void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
   208 
   209     /// \brief Return the item having minimum priority.
   210     ///
   211     /// This function returns the item having minimum priority.
   212     /// \pre The heap must be non-empty.
   213     Item top() const { return _data[0].first; }
   214 
   215     /// \brief The minimum priority.
   216     ///
   217     /// This function returns the minimum priority.
   218     /// \pre The heap must be non-empty.
   219     Prio prio() const { return _data[0].second; }
   220 
   221     /// \brief Remove the item having minimum priority.
   222     ///
   223     /// This function removes the item having minimum priority.
   224     /// \pre The heap must be non-empty.
   225     void pop() {
   226       int n = _data.size()-1;
   227       _iim.set(_data[0].first, POST_HEAP);
   228       if (n>0) bubbleDown(0, _data[n], n);
   229       _data.pop_back();
   230     }
   231 
   232     /// \brief Remove the given item from the heap.
   233     ///
   234     /// This function removes the given item from the heap if it is
   235     /// already stored.
   236     /// \param i The item to delete.
   237     /// \pre \e i must be in the heap.
   238     void erase(const Item &i) {
   239       int h = _iim[i];
   240       int n = _data.size()-1;
   241       _iim.set(_data[h].first, POST_HEAP);
   242       if( h<n ) {
   243         if( less(_data[parent(h)], _data[n]) )
   244           bubbleDown(h, _data[n], n);
   245         else
   246           bubbleUp(h, _data[n]);
   247       }
   248       _data.pop_back();
   249     }
   250 
   251     /// \brief The priority of the given item.
   252     ///
   253     /// This function returns the priority of the given item.
   254     /// \param i The item.
   255     /// \pre \e i must be in the heap.
   256     Prio operator[](const Item &i) const {
   257       int idx = _iim[i];
   258       return _data[idx].second;
   259     }
   260 
   261     /// \brief Set the priority of an item or insert it, if it is
   262     /// not stored in the heap.
   263     ///
   264     /// This method sets the priority of the given item if it is
   265     /// already stored in the heap. Otherwise it inserts the given
   266     /// item into the heap with the given priority.
   267     /// \param i The item.
   268     /// \param p The priority.
   269     void set(const Item &i, const Prio &p) {
   270       int idx = _iim[i];
   271       if( idx<0 )
   272         push(i,p);
   273       else if( _comp(p, _data[idx].second) )
   274         bubbleUp(idx, Pair(i,p));
   275       else
   276         bubbleDown(idx, Pair(i,p), _data.size());
   277     }
   278 
   279     /// \brief Decrease the priority of an item to the given value.
   280     ///
   281     /// This function decreases the priority of an item to the given value.
   282     /// \param i The item.
   283     /// \param p The priority.
   284     /// \pre \e i must be stored in the heap with priority at least \e p.
   285     void decrease(const Item &i, const Prio &p) {
   286       int idx = _iim[i];
   287       bubbleUp(idx, Pair(i,p));
   288     }
   289 
   290     /// \brief Increase the priority of an item to the given value.
   291     ///
   292     /// This function increases the priority of an item to the given value.
   293     /// \param i The item.
   294     /// \param p The priority.
   295     /// \pre \e i must be stored in the heap with priority at most \e p.
   296     void increase(const Item &i, const Prio &p) {
   297       int idx = _iim[i];
   298       bubbleDown(idx, Pair(i,p), _data.size());
   299     }
   300 
   301     /// \brief Return the state of an item.
   302     ///
   303     /// This method returns \c PRE_HEAP if the given item has never
   304     /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
   305     /// and \c POST_HEAP otherwise.
   306     /// In the latter case it is possible that the item will get back
   307     /// to the heap again.
   308     /// \param i The item.
   309     State state(const Item &i) const {
   310       int s = _iim[i];
   311       if (s>=0) s=0;
   312       return State(s);
   313     }
   314 
   315     /// \brief Set the state of an item in the heap.
   316     ///
   317     /// This function sets the state of the given item in the heap.
   318     /// It can be used to manually clear the heap when it is important
   319     /// to achive better time complexity.
   320     /// \param i The item.
   321     /// \param st The state. It should not be \c IN_HEAP.
   322     void state(const Item& i, State st) {
   323       switch (st) {
   324         case POST_HEAP:
   325         case PRE_HEAP:
   326           if (state(i) == IN_HEAP) erase(i);
   327           _iim[i] = st;
   328           break;
   329         case IN_HEAP:
   330           break;
   331       }
   332     }
   333 
   334     /// \brief Replace an item in the heap.
   335     ///
   336     /// This function replaces item \c i with item \c j.
   337     /// Item \c i must be in the heap, while \c j must be out of the heap.
   338     /// After calling this method, item \c i will be out of the
   339     /// heap and \c j will be in the heap with the same prioriority
   340     /// as item \c i had before.
   341     void replace(const Item& i, const Item& j) {
   342       int idx=_iim[i];
   343       _iim.set(i, _iim[j]);
   344       _iim.set(j, idx);
   345       _data[idx].first=j;
   346     }
   347 
   348   }; // class DHeap
   349 
   350 } // namespace lemon
   351 
   352 #endif // LEMON_DHEAP_H