lemon/radix_heap.h
author Peter Kovacs <kpeter@inf.elte.hu>
Sun, 23 Aug 2009 11:09:22 +0200
changeset 782 853fcddcf282
parent 728 532697c9fa53
child 756 0747f332c478
permissions -rw-r--r--
Doc improvements, fixes and unifications for graphs (#311)
deba@728
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@728
     2
 *
deba@728
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@728
     4
 *
deba@728
     5
 * Copyright (C) 2003-2009
deba@728
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@728
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@728
     8
 *
deba@728
     9
 * Permission to use, modify and distribute this software is granted
deba@728
    10
 * provided that this copyright notice appears in all copies. For
deba@728
    11
 * precise terms see the accompanying LICENSE file.
deba@728
    12
 *
deba@728
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@728
    14
 * express or implied, and with no claim as to its suitability for any
deba@728
    15
 * purpose.
deba@728
    16
 *
deba@728
    17
 */
deba@728
    18
deba@728
    19
#ifndef LEMON_RADIX_HEAP_H
deba@728
    20
#define LEMON_RADIX_HEAP_H
deba@728
    21
deba@728
    22
///\ingroup auxdat
deba@728
    23
///\file
deba@728
    24
///\brief Radix Heap implementation.
deba@728
    25
deba@728
    26
#include <vector>
deba@728
    27
#include <lemon/error.h>
deba@728
    28
deba@728
    29
namespace lemon {
deba@728
    30
deba@728
    31
deba@728
    32
  /// \ingroup auxdata
deba@728
    33
  ///
deba@728
    34
  /// \brief A Radix Heap implementation.
deba@728
    35
  ///
deba@728
    36
  /// This class implements the \e radix \e heap data structure. A \e heap
deba@728
    37
  /// is a data structure for storing items with specified values called \e
deba@728
    38
  /// priorities in such a way that finding the item with minimum priority is
deba@728
    39
  /// efficient. This heap type can store only items with \e int priority.
deba@728
    40
  /// In a heap one can change the priority of an item, add or erase an
deba@728
    41
  /// item, but the priority cannot be decreased under the last removed
deba@728
    42
  /// item's priority.
deba@728
    43
  ///
deba@730
    44
  /// \param IM A read and writable Item int map, used internally
deba@728
    45
  /// to handle the cross references.
deba@728
    46
  ///
deba@728
    47
  /// \see BinHeap
deba@728
    48
  /// \see Dijkstra
deba@730
    49
  template <typename IM>
deba@728
    50
  class RadixHeap {
deba@728
    51
deba@728
    52
  public:
deba@730
    53
    typedef typename IM::Key Item;
deba@728
    54
    typedef int Prio;
deba@730
    55
    typedef IM ItemIntMap;
deba@728
    56
deba@728
    57
    /// \brief Exception thrown by RadixHeap.
deba@728
    58
    ///
deba@728
    59
    /// This Exception is thrown when a smaller priority
deba@728
    60
    /// is inserted into the \e RadixHeap then the last time erased.
deba@728
    61
    /// \see RadixHeap
deba@728
    62
deba@728
    63
    class UnderFlowPriorityError : public Exception {
deba@728
    64
    public:
deba@728
    65
      virtual const char* what() const throw() {
deba@728
    66
        return "lemon::RadixHeap::UnderFlowPriorityError";
deba@728
    67
      }
deba@728
    68
    };
deba@728
    69
deba@728
    70
    /// \brief Type to represent the items states.
deba@728
    71
    ///
deba@728
    72
    /// Each Item element have a state associated to it. It may be "in heap",
deba@728
    73
    /// "pre heap" or "post heap". The latter two are indifferent from the
deba@728
    74
    /// heap's point of view, but may be useful to the user.
deba@728
    75
    ///
deba@728
    76
    /// The ItemIntMap \e should be initialized in such way that it maps
deba@728
    77
    /// PRE_HEAP (-1) to any element to be put in the heap...
deba@728
    78
    enum State {
deba@728
    79
      IN_HEAP = 0,
deba@728
    80
      PRE_HEAP = -1,
deba@728
    81
      POST_HEAP = -2
deba@728
    82
    };
deba@728
    83
deba@728
    84
  private:
deba@728
    85
deba@728
    86
    struct RadixItem {
deba@728
    87
      int prev, next, box;
deba@728
    88
      Item item;
deba@728
    89
      int prio;
deba@728
    90
      RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {}
deba@728
    91
    };
deba@728
    92
deba@728
    93
    struct RadixBox {
deba@728
    94
      int first;
deba@728
    95
      int min, size;
deba@728
    96
      RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {}
deba@728
    97
    };
deba@728
    98
deba@728
    99
    std::vector<RadixItem> data;
deba@728
   100
    std::vector<RadixBox> boxes;
deba@728
   101
deba@730
   102
    ItemIntMap &_iim;
deba@728
   103
deba@728
   104
deba@728
   105
  public:
deba@728
   106
    /// \brief The constructor.
deba@728
   107
    ///
deba@728
   108
    /// The constructor.
deba@728
   109
    ///
deba@730
   110
    /// \param map It should be given to the constructor, since it is used
deba@728
   111
    /// internally to handle the cross references. The value of the map
deba@728
   112
    /// should be PRE_HEAP (-1) for each element.
deba@728
   113
    ///
deba@728
   114
    /// \param minimal The initial minimal value of the heap.
deba@728
   115
    /// \param capacity It determines the initial capacity of the heap.
deba@730
   116
    RadixHeap(ItemIntMap &map, int minimal = 0, int capacity = 0)
deba@730
   117
      : _iim(map) {
deba@728
   118
      boxes.push_back(RadixBox(minimal, 1));
deba@728
   119
      boxes.push_back(RadixBox(minimal + 1, 1));
deba@728
   120
      while (lower(boxes.size() - 1, capacity + minimal - 1)) {
deba@728
   121
        extend();
deba@728
   122
      }
deba@728
   123
    }
deba@728
   124
deba@728
   125
    /// The number of items stored in the heap.
deba@728
   126
    ///
deba@728
   127
    /// \brief Returns the number of items stored in the heap.
deba@728
   128
    int size() const { return data.size(); }
deba@728
   129
    /// \brief Checks if the heap stores no items.
deba@728
   130
    ///
deba@728
   131
    /// Returns \c true if and only if the heap stores no items.
deba@728
   132
    bool empty() const { return data.empty(); }
deba@728
   133
deba@728
   134
    /// \brief Make empty this heap.
deba@728
   135
    ///
deba@728
   136
    /// Make empty this heap. It does not change the cross reference
deba@728
   137
    /// map.  If you want to reuse a heap what is not surely empty you
deba@728
   138
    /// should first clear the heap and after that you should set the
deba@728
   139
    /// cross reference map for each item to \c PRE_HEAP.
deba@728
   140
    void clear(int minimal = 0, int capacity = 0) {
deba@728
   141
      data.clear(); boxes.clear();
deba@728
   142
      boxes.push_back(RadixBox(minimal, 1));
deba@728
   143
      boxes.push_back(RadixBox(minimal + 1, 1));
deba@728
   144
      while (lower(boxes.size() - 1, capacity + minimal - 1)) {
deba@728
   145
        extend();
deba@728
   146
      }
deba@728
   147
    }
deba@728
   148
deba@728
   149
  private:
deba@728
   150
deba@728
   151
    bool upper(int box, Prio pr) {
deba@728
   152
      return pr < boxes[box].min;
deba@728
   153
    }
deba@728
   154
deba@728
   155
    bool lower(int box, Prio pr) {
deba@728
   156
      return pr >= boxes[box].min + boxes[box].size;
deba@728
   157
    }
deba@728
   158
deba@728
   159
    /// \brief Remove item from the box list.
deba@728
   160
    void remove(int index) {
deba@728
   161
      if (data[index].prev >= 0) {
deba@728
   162
        data[data[index].prev].next = data[index].next;
deba@728
   163
      } else {
deba@728
   164
        boxes[data[index].box].first = data[index].next;
deba@728
   165
      }
deba@728
   166
      if (data[index].next >= 0) {
deba@728
   167
        data[data[index].next].prev = data[index].prev;
deba@728
   168
      }
deba@728
   169
    }
deba@728
   170
deba@728
   171
    /// \brief Insert item into the box list.
deba@728
   172
    void insert(int box, int index) {
deba@728
   173
      if (boxes[box].first == -1) {
deba@728
   174
        boxes[box].first = index;
deba@728
   175
        data[index].next = data[index].prev = -1;
deba@728
   176
      } else {
deba@728
   177
        data[index].next = boxes[box].first;
deba@728
   178
        data[boxes[box].first].prev = index;
deba@728
   179
        data[index].prev = -1;
deba@728
   180
        boxes[box].first = index;
deba@728
   181
      }
deba@728
   182
      data[index].box = box;
deba@728
   183
    }
deba@728
   184
deba@728
   185
    /// \brief Add a new box to the box list.
deba@728
   186
    void extend() {
deba@728
   187
      int min = boxes.back().min + boxes.back().size;
deba@728
   188
      int bs = 2 * boxes.back().size;
deba@728
   189
      boxes.push_back(RadixBox(min, bs));
deba@728
   190
    }
deba@728
   191
deba@728
   192
    /// \brief Move an item up into the proper box.
deba@728
   193
    void bubble_up(int index) {
deba@728
   194
      if (!lower(data[index].box, data[index].prio)) return;
deba@728
   195
      remove(index);
deba@728
   196
      int box = findUp(data[index].box, data[index].prio);
deba@728
   197
      insert(box, index);
deba@728
   198
    }
deba@728
   199
deba@728
   200
    /// \brief Find up the proper box for the item with the given prio.
deba@728
   201
    int findUp(int start, int pr) {
deba@728
   202
      while (lower(start, pr)) {
deba@728
   203
        if (++start == int(boxes.size())) {
deba@728
   204
          extend();
deba@728
   205
        }
deba@728
   206
      }
deba@728
   207
      return start;
deba@728
   208
    }
deba@728
   209
deba@728
   210
    /// \brief Move an item down into the proper box.
deba@728
   211
    void bubble_down(int index) {
deba@728
   212
      if (!upper(data[index].box, data[index].prio)) return;
deba@728
   213
      remove(index);
deba@728
   214
      int box = findDown(data[index].box, data[index].prio);
deba@728
   215
      insert(box, index);
deba@728
   216
    }
deba@728
   217
deba@728
   218
    /// \brief Find up the proper box for the item with the given prio.
deba@728
   219
    int findDown(int start, int pr) {
deba@728
   220
      while (upper(start, pr)) {
deba@728
   221
        if (--start < 0) throw UnderFlowPriorityError();
deba@728
   222
      }
deba@728
   223
      return start;
deba@728
   224
    }
deba@728
   225
deba@728
   226
    /// \brief Find the first not empty box.
deba@728
   227
    int findFirst() {
deba@728
   228
      int first = 0;
deba@728
   229
      while (boxes[first].first == -1) ++first;
deba@728
   230
      return first;
deba@728
   231
    }
deba@728
   232
deba@728
   233
    /// \brief Gives back the minimal prio of the box.
deba@728
   234
    int minValue(int box) {
deba@728
   235
      int min = data[boxes[box].first].prio;
deba@728
   236
      for (int k = boxes[box].first; k != -1; k = data[k].next) {
deba@728
   237
        if (data[k].prio < min) min = data[k].prio;
deba@728
   238
      }
deba@728
   239
      return min;
deba@728
   240
    }
deba@728
   241
deba@728
   242
    /// \brief Rearrange the items of the heap and makes the
deba@728
   243
    /// first box not empty.
deba@728
   244
    void moveDown() {
deba@728
   245
      int box = findFirst();
deba@728
   246
      if (box == 0) return;
deba@728
   247
      int min = minValue(box);
deba@728
   248
      for (int i = 0; i <= box; ++i) {
deba@728
   249
        boxes[i].min = min;
deba@728
   250
        min += boxes[i].size;
deba@728
   251
      }
deba@728
   252
      int curr = boxes[box].first, next;
deba@728
   253
      while (curr != -1) {
deba@728
   254
        next = data[curr].next;
deba@728
   255
        bubble_down(curr);
deba@728
   256
        curr = next;
deba@728
   257
      }
deba@728
   258
    }
deba@728
   259
deba@728
   260
    void relocate_last(int index) {
deba@728
   261
      if (index != int(data.size()) - 1) {
deba@728
   262
        data[index] = data.back();
deba@728
   263
        if (data[index].prev != -1) {
deba@728
   264
          data[data[index].prev].next = index;
deba@728
   265
        } else {
deba@728
   266
          boxes[data[index].box].first = index;
deba@728
   267
        }
deba@728
   268
        if (data[index].next != -1) {
deba@728
   269
          data[data[index].next].prev = index;
deba@728
   270
        }
deba@730
   271
        _iim[data[index].item] = index;
deba@728
   272
      }
deba@728
   273
      data.pop_back();
deba@728
   274
    }
deba@728
   275
deba@728
   276
  public:
deba@728
   277
deba@728
   278
    /// \brief Insert an item into the heap with the given priority.
deba@728
   279
    ///
deba@728
   280
    /// Adds \c i to the heap with priority \c p.
deba@728
   281
    /// \param i The item to insert.
deba@728
   282
    /// \param p The priority of the item.
deba@728
   283
    void push(const Item &i, const Prio &p) {
deba@728
   284
      int n = data.size();
deba@730
   285
      _iim.set(i, n);
deba@728
   286
      data.push_back(RadixItem(i, p));
deba@728
   287
      while (lower(boxes.size() - 1, p)) {
deba@728
   288
        extend();
deba@728
   289
      }
deba@728
   290
      int box = findDown(boxes.size() - 1, p);
deba@728
   291
      insert(box, n);
deba@728
   292
    }
deba@728
   293
deba@728
   294
    /// \brief Returns the item with minimum priority.
deba@728
   295
    ///
deba@728
   296
    /// This method returns the item with minimum priority.
deba@728
   297
    /// \pre The heap must be nonempty.
deba@728
   298
    Item top() const {
deba@728
   299
      const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
deba@728
   300
      return data[boxes[0].first].item;
deba@728
   301
    }
deba@728
   302
deba@728
   303
    /// \brief Returns the minimum priority.
deba@728
   304
    ///
deba@728
   305
    /// It returns the minimum priority.
deba@728
   306
    /// \pre The heap must be nonempty.
deba@728
   307
    Prio prio() const {
deba@728
   308
      const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
deba@728
   309
      return data[boxes[0].first].prio;
deba@728
   310
     }
deba@728
   311
deba@728
   312
    /// \brief Deletes the item with minimum priority.
deba@728
   313
    ///
deba@728
   314
    /// This method deletes the item with minimum priority.
deba@728
   315
    /// \pre The heap must be non-empty.
deba@728
   316
    void pop() {
deba@728
   317
      moveDown();
deba@728
   318
      int index = boxes[0].first;
deba@730
   319
      _iim[data[index].item] = POST_HEAP;
deba@728
   320
      remove(index);
deba@728
   321
      relocate_last(index);
deba@728
   322
    }
deba@728
   323
deba@728
   324
    /// \brief Deletes \c i from the heap.
deba@728
   325
    ///
deba@728
   326
    /// This method deletes item \c i from the heap, if \c i was
deba@728
   327
    /// already stored in the heap.
deba@728
   328
    /// \param i The item to erase.
deba@728
   329
    void erase(const Item &i) {
deba@730
   330
      int index = _iim[i];
deba@730
   331
      _iim[i] = POST_HEAP;
deba@728
   332
      remove(index);
deba@728
   333
      relocate_last(index);
deba@728
   334
   }
deba@728
   335
deba@728
   336
    /// \brief Returns the priority of \c i.
deba@728
   337
    ///
deba@728
   338
    /// This function returns the priority of item \c i.
deba@728
   339
    /// \pre \c i must be in the heap.
deba@728
   340
    /// \param i The item.
deba@728
   341
    Prio operator[](const Item &i) const {
deba@730
   342
      int idx = _iim[i];
deba@728
   343
      return data[idx].prio;
deba@728
   344
    }
deba@728
   345
deba@728
   346
    /// \brief \c i gets to the heap with priority \c p independently
deba@728
   347
    /// if \c i was already there.
deba@728
   348
    ///
deba@728
   349
    /// This method calls \ref push(\c i, \c p) if \c i is not stored
deba@728
   350
    /// in the heap and sets the priority of \c i to \c p otherwise.
deba@728
   351
    /// It may throw an \e UnderFlowPriorityException.
deba@728
   352
    /// \param i The item.
deba@728
   353
    /// \param p The priority.
deba@728
   354
    void set(const Item &i, const Prio &p) {
deba@730
   355
      int idx = _iim[i];
deba@728
   356
      if( idx < 0 ) {
deba@728
   357
        push(i, p);
deba@728
   358
      }
deba@728
   359
      else if( p >= data[idx].prio ) {
deba@728
   360
        data[idx].prio = p;
deba@728
   361
        bubble_up(idx);
deba@728
   362
      } else {
deba@728
   363
        data[idx].prio = p;
deba@728
   364
        bubble_down(idx);
deba@728
   365
      }
deba@728
   366
    }
deba@728
   367
deba@728
   368
deba@728
   369
    /// \brief Decreases the priority of \c i to \c p.
deba@728
   370
    ///
deba@728
   371
    /// This method decreases the priority of item \c i to \c p.
deba@728
   372
    /// \pre \c i must be stored in the heap with priority at least \c p, and
deba@728
   373
    /// \c should be greater or equal to the last removed item's priority.
deba@728
   374
    /// \param i The item.
deba@728
   375
    /// \param p The priority.
deba@728
   376
    void decrease(const Item &i, const Prio &p) {
deba@730
   377
      int idx = _iim[i];
deba@728
   378
      data[idx].prio = p;
deba@728
   379
      bubble_down(idx);
deba@728
   380
    }
deba@728
   381
deba@728
   382
    /// \brief Increases the priority of \c i to \c p.
deba@728
   383
    ///
deba@728
   384
    /// This method sets the priority of item \c i to \c p.
deba@728
   385
    /// \pre \c i must be stored in the heap with priority at most \c p
deba@728
   386
    /// \param i The item.
deba@728
   387
    /// \param p The priority.
deba@728
   388
    void increase(const Item &i, const Prio &p) {
deba@730
   389
      int idx = _iim[i];
deba@728
   390
      data[idx].prio = p;
deba@728
   391
      bubble_up(idx);
deba@728
   392
    }
deba@728
   393
deba@728
   394
    /// \brief Returns if \c item is in, has already been in, or has
deba@728
   395
    /// never been in the heap.
deba@728
   396
    ///
deba@728
   397
    /// This method returns PRE_HEAP if \c item has never been in the
deba@728
   398
    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
deba@728
   399
    /// otherwise. In the latter case it is possible that \c item will
deba@728
   400
    /// get back to the heap again.
deba@728
   401
    /// \param i The item.
deba@728
   402
    State state(const Item &i) const {
deba@730
   403
      int s = _iim[i];
deba@728
   404
      if( s >= 0 ) s = 0;
deba@728
   405
      return State(s);
deba@728
   406
    }
deba@728
   407
deba@728
   408
    /// \brief Sets the state of the \c item in the heap.
deba@728
   409
    ///
deba@728
   410
    /// Sets the state of the \c item in the heap. It can be used to
deba@728
   411
    /// manually clear the heap when it is important to achive the
deba@728
   412
    /// better time complexity.
deba@728
   413
    /// \param i The item.
deba@728
   414
    /// \param st The state. It should not be \c IN_HEAP.
deba@728
   415
    void state(const Item& i, State st) {
deba@728
   416
      switch (st) {
deba@728
   417
      case POST_HEAP:
deba@728
   418
      case PRE_HEAP:
deba@728
   419
        if (state(i) == IN_HEAP) {
deba@728
   420
          erase(i);
deba@728
   421
        }
deba@730
   422
        _iim[i] = st;
deba@728
   423
        break;
deba@728
   424
      case IN_HEAP:
deba@728
   425
        break;
deba@728
   426
      }
deba@728
   427
    }
deba@728
   428
deba@728
   429
  }; // class RadixHeap
deba@728
   430
deba@728
   431
} // namespace lemon
deba@728
   432
deba@728
   433
#endif // LEMON_RADIX_HEAP_H