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