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