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