lemon/fourary_heap.h
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 12 Nov 2009 23:26:13 +0100
changeset 806 fa6f37d7a25b
parent 705 39a5b48bcace
permissions -rw-r--r--
Entirely rework CapacityScaling (#180)

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