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