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