lemon/bin_heap.h
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 894 bb70ad62c95f
parent 559 c5fd2d996909
child 683 9f529abcaebf
permissions -rw-r--r--
Fix critical bug in preflow (#372)

The wrong transition between the bound decrease and highest active
heuristics caused the bug. The last node chosen in bound decrease mode
is used in the first iteration in highest active mode.
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
alpar@100
    22
///\ingroup auxdat
alpar@100
    23
///\file
alpar@100
    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
alpar@100
    32
  ///\ingroup auxdat
alpar@100
    33
  ///
alpar@100
    34
  ///\brief A Binary Heap implementation.
alpar@100
    35
  ///
kpeter@559
    36
  ///This class implements the \e binary \e heap data structure. 
kpeter@559
    37
  /// 
kpeter@559
    38
  ///A \e heap is a data structure for storing items with specified values
kpeter@559
    39
  ///called \e priorities in such a way that finding the item with minimum
kpeter@559
    40
  ///priority is efficient. \c Comp specifies the ordering of the priorities.
kpeter@559
    41
  ///In a heap one can change the priority of an item, add or erase an
kpeter@559
    42
  ///item, etc.
alpar@100
    43
  ///
kpeter@559
    44
  ///\tparam PR Type of the priority of the items.
kpeter@559
    45
  ///\tparam IM A read and writable item map with int values, used internally
alpar@100
    46
  ///to handle the cross references.
kpeter@559
    47
  ///\tparam Comp A functor class for the ordering of the priorities.
kpeter@559
    48
  ///The default is \c std::less<PR>.
alpar@100
    49
  ///
alpar@100
    50
  ///\sa FibHeap
alpar@100
    51
  ///\sa Dijkstra
kpeter@559
    52
  template <typename PR, typename IM, typename Comp = std::less<PR> >
alpar@100
    53
  class BinHeap {
alpar@100
    54
alpar@100
    55
  public:
alpar@100
    56
    ///\e
kpeter@559
    57
    typedef IM ItemIntMap;
alpar@100
    58
    ///\e
kpeter@559
    59
    typedef PR Prio;
alpar@100
    60
    ///\e
alpar@100
    61
    typedef typename ItemIntMap::Key Item;
alpar@100
    62
    ///\e
alpar@100
    63
    typedef std::pair<Item,Prio> Pair;
alpar@100
    64
    ///\e
kpeter@559
    65
    typedef Comp Compare;
alpar@100
    66
alpar@100
    67
    /// \brief Type to represent the items states.
alpar@100
    68
    ///
alpar@100
    69
    /// Each Item element have a state associated to it. It may be "in heap",
alpar@100
    70
    /// "pre heap" or "post heap". The latter two are indifferent from the
alpar@100
    71
    /// heap's point of view, but may be useful to the user.
alpar@100
    72
    ///
kpeter@559
    73
    /// The item-int map must be initialized in such way that it assigns
kpeter@559
    74
    /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
alpar@100
    75
    enum State {
kpeter@584
    76
      IN_HEAP = 0,    ///< = 0.
kpeter@584
    77
      PRE_HEAP = -1,  ///< = -1.
kpeter@584
    78
      POST_HEAP = -2  ///< = -2.
alpar@100
    79
    };
alpar@100
    80
alpar@100
    81
  private:
kpeter@559
    82
    std::vector<Pair> _data;
kpeter@559
    83
    Compare _comp;
kpeter@559
    84
    ItemIntMap &_iim;
alpar@100
    85
alpar@100
    86
  public:
alpar@100
    87
    /// \brief The constructor.
alpar@100
    88
    ///
alpar@100
    89
    /// The constructor.
kpeter@559
    90
    /// \param map should be given to the constructor, since it is used
alpar@100
    91
    /// internally to handle the cross references. The value of the map
kpeter@559
    92
    /// must be \c PRE_HEAP (<tt>-1</tt>) for every item.
kpeter@559
    93
    explicit BinHeap(ItemIntMap &map) : _iim(map) {}
alpar@209
    94
alpar@100
    95
    /// \brief The constructor.
alpar@100
    96
    ///
alpar@100
    97
    /// The constructor.
kpeter@559
    98
    /// \param map should be given to the constructor, since it is used
alpar@100
    99
    /// internally to handle the cross references. The value of the map
alpar@100
   100
    /// should be PRE_HEAP (-1) for each element.
alpar@100
   101
    ///
kpeter@559
   102
    /// \param comp The comparator function object.
kpeter@559
   103
    BinHeap(ItemIntMap &map, const Compare &comp)
kpeter@559
   104
      : _iim(map), _comp(comp) {}
alpar@100
   105
alpar@100
   106
alpar@100
   107
    /// The number of items stored in the heap.
alpar@100
   108
    ///
alpar@100
   109
    /// \brief Returns the number of items stored in the heap.
kpeter@559
   110
    int size() const { return _data.size(); }
alpar@209
   111
alpar@100
   112
    /// \brief Checks if the heap stores no items.
alpar@100
   113
    ///
alpar@100
   114
    /// Returns \c true if and only if the heap stores no items.
kpeter@559
   115
    bool empty() const { return _data.empty(); }
alpar@100
   116
alpar@100
   117
    /// \brief Make empty this heap.
alpar@209
   118
    ///
alpar@100
   119
    /// Make empty this heap. It does not change the cross reference map.
alpar@100
   120
    /// If you want to reuse what is not surely empty you should first clear
alpar@100
   121
    /// the heap and after that you should set the cross reference map for
alpar@100
   122
    /// each item to \c PRE_HEAP.
alpar@209
   123
    void clear() {
kpeter@559
   124
      _data.clear();
alpar@100
   125
    }
alpar@100
   126
alpar@100
   127
  private:
alpar@100
   128
    static int parent(int i) { return (i-1)/2; }
alpar@100
   129
alpar@100
   130
    static int second_child(int i) { return 2*i+2; }
alpar@100
   131
    bool less(const Pair &p1, const Pair &p2) const {
kpeter@559
   132
      return _comp(p1.second, p2.second);
alpar@100
   133
    }
alpar@100
   134
alpar@100
   135
    int bubble_up(int hole, Pair p) {
alpar@100
   136
      int par = parent(hole);
kpeter@559
   137
      while( hole>0 && less(p,_data[par]) ) {
kpeter@559
   138
        move(_data[par],hole);
alpar@209
   139
        hole = par;
alpar@209
   140
        par = parent(hole);
alpar@100
   141
      }
alpar@100
   142
      move(p, hole);
alpar@100
   143
      return hole;
alpar@100
   144
    }
alpar@100
   145
alpar@100
   146
    int bubble_down(int hole, Pair p, int length) {
alpar@100
   147
      int child = second_child(hole);
alpar@100
   148
      while(child < length) {
kpeter@559
   149
        if( less(_data[child-1], _data[child]) ) {
alpar@209
   150
          --child;
alpar@209
   151
        }
kpeter@559
   152
        if( !less(_data[child], p) )
alpar@209
   153
          goto ok;
kpeter@559
   154
        move(_data[child], hole);
alpar@209
   155
        hole = child;
alpar@209
   156
        child = second_child(hole);
alpar@100
   157
      }
alpar@100
   158
      child--;
kpeter@559
   159
      if( child<length && less(_data[child], p) ) {
kpeter@559
   160
        move(_data[child], hole);
alpar@209
   161
        hole=child;
alpar@100
   162
      }
alpar@100
   163
    ok:
alpar@100
   164
      move(p, hole);
alpar@100
   165
      return hole;
alpar@100
   166
    }
alpar@100
   167
alpar@100
   168
    void move(const Pair &p, int i) {
kpeter@559
   169
      _data[i] = p;
kpeter@559
   170
      _iim.set(p.first, i);
alpar@100
   171
    }
alpar@100
   172
alpar@100
   173
  public:
alpar@100
   174
    /// \brief Insert a pair of item and priority into the heap.
alpar@100
   175
    ///
alpar@100
   176
    /// Adds \c p.first to the heap with priority \c p.second.
alpar@100
   177
    /// \param p The pair to insert.
alpar@100
   178
    void push(const Pair &p) {
kpeter@559
   179
      int n = _data.size();
kpeter@559
   180
      _data.resize(n+1);
alpar@100
   181
      bubble_up(n, p);
alpar@100
   182
    }
alpar@100
   183
alpar@100
   184
    /// \brief Insert an item into the heap with the given heap.
alpar@209
   185
    ///
alpar@209
   186
    /// Adds \c i to the heap with priority \c p.
alpar@100
   187
    /// \param i The item to insert.
alpar@100
   188
    /// \param p The priority of the item.
alpar@100
   189
    void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
alpar@100
   190
alpar@100
   191
    /// \brief Returns the item with minimum priority relative to \c Compare.
alpar@100
   192
    ///
alpar@100
   193
    /// This method returns the item with minimum priority relative to \c
alpar@209
   194
    /// Compare.
alpar@209
   195
    /// \pre The heap must be nonempty.
alpar@100
   196
    Item top() const {
kpeter@559
   197
      return _data[0].first;
alpar@100
   198
    }
alpar@100
   199
alpar@100
   200
    /// \brief Returns the minimum priority relative to \c Compare.
alpar@100
   201
    ///
alpar@100
   202
    /// It returns the minimum priority relative to \c Compare.
alpar@100
   203
    /// \pre The heap must be nonempty.
alpar@100
   204
    Prio prio() const {
kpeter@559
   205
      return _data[0].second;
alpar@100
   206
    }
alpar@100
   207
alpar@100
   208
    /// \brief Deletes the item with minimum priority relative to \c Compare.
alpar@100
   209
    ///
alpar@100
   210
    /// This method deletes the item with minimum priority relative to \c
alpar@209
   211
    /// Compare from the heap.
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@559
   217
        bubble_down(0, _data[n], n);
alpar@100
   218
      }
kpeter@559
   219
      _data.pop_back();
alpar@100
   220
    }
alpar@100
   221
alpar@100
   222
    /// \brief Deletes \c i from the heap.
alpar@100
   223
    ///
alpar@100
   224
    /// This method deletes item \c i from the heap.
alpar@100
   225
    /// \param i The item to erase.
alpar@100
   226
    /// \pre The item should be in the heap.
alpar@100
   227
    void erase(const Item &i) {
kpeter@559
   228
      int h = _iim[i];
kpeter@559
   229
      int n = _data.size()-1;
kpeter@559
   230
      _iim.set(_data[h].first, POST_HEAP);
alpar@100
   231
      if( h < n ) {
kpeter@559
   232
        if ( bubble_up(h, _data[n]) == h) {
kpeter@559
   233
          bubble_down(h, _data[n], n);
alpar@209
   234
        }
alpar@100
   235
      }
kpeter@559
   236
      _data.pop_back();
alpar@100
   237
    }
alpar@100
   238
alpar@209
   239
alpar@100
   240
    /// \brief Returns the priority of \c i.
alpar@100
   241
    ///
alpar@209
   242
    /// This function returns the priority of item \c i.
kpeter@559
   243
    /// \param i The item.
alpar@100
   244
    /// \pre \c 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
alpar@209
   250
    /// \brief \c i gets to the heap with priority \c p independently
alpar@100
   251
    /// if \c i was already there.
alpar@100
   252
    ///
alpar@100
   253
    /// This method calls \ref push(\c i, \c p) if \c i is not stored
alpar@100
   254
    /// in the heap and sets the priority of \c i to \c p otherwise.
alpar@100
   255
    /// \param i The item.
alpar@100
   256
    /// \param p The priority.
alpar@100
   257
    void set(const Item &i, const Prio &p) {
kpeter@559
   258
      int idx = _iim[i];
alpar@100
   259
      if( idx < 0 ) {
alpar@209
   260
        push(i,p);
alpar@100
   261
      }
kpeter@559
   262
      else if( _comp(p, _data[idx].second) ) {
alpar@209
   263
        bubble_up(idx, Pair(i,p));
alpar@100
   264
      }
alpar@100
   265
      else {
kpeter@559
   266
        bubble_down(idx, Pair(i,p), _data.size());
alpar@100
   267
      }
alpar@100
   268
    }
alpar@100
   269
alpar@100
   270
    /// \brief Decreases the priority of \c i to \c p.
alpar@100
   271
    ///
alpar@100
   272
    /// This method decreases the priority of item \c i to \c p.
kpeter@559
   273
    /// \param i The item.
kpeter@559
   274
    /// \param p The priority.
alpar@100
   275
    /// \pre \c i must be stored in the heap with priority at least \c
alpar@100
   276
    /// p relative to \c Compare.
alpar@100
   277
    void decrease(const Item &i, const Prio &p) {
kpeter@559
   278
      int idx = _iim[i];
alpar@100
   279
      bubble_up(idx, Pair(i,p));
alpar@100
   280
    }
alpar@209
   281
alpar@100
   282
    /// \brief Increases the priority of \c i to \c p.
alpar@100
   283
    ///
alpar@209
   284
    /// This method sets the priority of item \c i to \c p.
kpeter@559
   285
    /// \param i The item.
kpeter@559
   286
    /// \param p The priority.
alpar@100
   287
    /// \pre \c i must be stored in the heap with priority at most \c
alpar@100
   288
    /// p relative to \c Compare.
alpar@100
   289
    void increase(const Item &i, const Prio &p) {
kpeter@559
   290
      int idx = _iim[i];
kpeter@559
   291
      bubble_down(idx, Pair(i,p), _data.size());
alpar@100
   292
    }
alpar@100
   293
alpar@209
   294
    /// \brief Returns if \c item is in, has already been in, or has
alpar@100
   295
    /// never been in the heap.
alpar@100
   296
    ///
alpar@100
   297
    /// This method returns PRE_HEAP if \c item has never been in the
alpar@100
   298
    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
alpar@100
   299
    /// otherwise. In the latter case it is possible that \c item will
alpar@100
   300
    /// get back to the heap again.
alpar@100
   301
    /// \param i The item.
alpar@100
   302
    State state(const Item &i) const {
kpeter@559
   303
      int s = _iim[i];
alpar@100
   304
      if( s>=0 )
alpar@209
   305
        s=0;
alpar@100
   306
      return State(s);
alpar@100
   307
    }
alpar@100
   308
alpar@100
   309
    /// \brief Sets the state of the \c item in the heap.
alpar@100
   310
    ///
alpar@100
   311
    /// Sets the state of the \c item in the heap. It can be used to
alpar@100
   312
    /// manually clear the heap when it is important to achive the
alpar@100
   313
    /// better time complexity.
alpar@100
   314
    /// \param i The item.
alpar@209
   315
    /// \param st The state. It should not be \c IN_HEAP.
alpar@100
   316
    void state(const Item& i, State st) {
alpar@100
   317
      switch (st) {
alpar@100
   318
      case POST_HEAP:
alpar@100
   319
      case PRE_HEAP:
alpar@100
   320
        if (state(i) == IN_HEAP) {
alpar@100
   321
          erase(i);
alpar@100
   322
        }
kpeter@559
   323
        _iim[i] = st;
alpar@100
   324
        break;
alpar@100
   325
      case IN_HEAP:
alpar@100
   326
        break;
alpar@100
   327
      }
alpar@100
   328
    }
alpar@100
   329
alpar@100
   330
    /// \brief Replaces an item in the heap.
alpar@100
   331
    ///
alpar@100
   332
    /// The \c i item is replaced with \c j item. The \c i item should
alpar@100
   333
    /// be in the heap, while the \c j should be out of the heap. The
alpar@100
   334
    /// \c i item will out of the heap and \c j will be in the heap
alpar@100
   335
    /// with the same prioriority as prevoiusly the \c i item.
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