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