3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2007
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #ifndef LEMON_RADIX_HEAP_H
20 #define LEMON_RADIX_HEAP_H
24 ///\brief Radix Heap implementation.
27 #include <lemon/error.h>
31 /// \brief Exception thrown by RadixHeap.
33 /// This Exception is thrown when a smaller priority
34 /// is inserted into the \e RadixHeap then the last time erased.
36 /// \author Balazs Dezso
38 class UnderFlowPriorityError : public RuntimeError {
40 virtual const char* what() const throw() {
41 return "lemon::UnderFlowPriorityError";
47 /// \brief A Radix Heap implementation.
49 /// This class implements the \e radix \e heap data structure. A \e heap
50 /// is a data structure for storing items with specified values called \e
51 /// priorities in such a way that finding the item with minimum priority is
52 /// efficient. This heap type can store only items with \e int priority.
53 /// In a heap one can change the priority of an item, add or erase an
54 /// item, but the priority cannot be decreased under the last removed
57 /// \param _ItemIntMap A read and writable Item int map, used internally
58 /// to handle the cross references.
62 /// \author Balazs Dezso
64 template <typename _ItemIntMap>
68 typedef typename _ItemIntMap::Key Item;
70 typedef _ItemIntMap ItemIntMap;
72 /// \brief Type to represent the items states.
74 /// Each Item element have a state associated to it. It may be "in heap",
75 /// "pre heap" or "post heap". The latter two are indifferent from the
76 /// heap's point of view, but may be useful to the user.
78 /// The ItemIntMap \e should be initialized in such way that it maps
79 /// PRE_HEAP (-1) to any element to be put in the heap...
92 RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {}
98 RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {}
101 std::vector<RadixItem> data;
102 std::vector<RadixBox> boxes;
108 /// \brief The constructor.
112 /// \param _iim It should be given to the constructor, since it is used
113 /// internally to handle the cross references. The value of the map
114 /// should be PRE_HEAP (-1) for each element.
116 /// \param minimal The initial minimal value of the heap.
117 /// \param capacity It determines the initial capacity of the heap.
118 RadixHeap(ItemIntMap &_iim, int minimal = 0, int capacity = 0)
120 boxes.push_back(RadixBox(minimal, 1));
121 boxes.push_back(RadixBox(minimal + 1, 1));
122 while (lower(boxes.size() - 1, capacity + minimal - 1)) {
127 /// The number of items stored in the heap.
129 /// \brief Returns the number of items stored in the heap.
130 int size() const { return data.size(); }
131 /// \brief Checks if the heap stores no items.
133 /// Returns \c true if and only if the heap stores no items.
134 bool empty() const { return data.empty(); }
136 /// \brief Make empty this heap.
138 /// Make empty this heap. It does not change the cross reference
139 /// map. If you want to reuse a heap what is not surely empty you
140 /// should first clear the heap and after that you should set the
141 /// cross reference map for each item to \c PRE_HEAP.
142 void clear(int minimal = 0, int capacity = 0) {
143 data.clear(); boxes.clear();
144 boxes.push_back(RadixBox(minimal, 1));
145 boxes.push_back(RadixBox(minimal + 1, 1));
146 while (lower(boxes.size() - 1, capacity + minimal - 1)) {
153 bool upper(int box, Prio pr) {
154 return pr < boxes[box].min;
157 bool lower(int box, Prio pr) {
158 return pr >= boxes[box].min + boxes[box].size;
161 /// \brief Remove item from the box list.
162 void remove(int index) {
163 if (data[index].prev >= 0) {
164 data[data[index].prev].next = data[index].next;
166 boxes[data[index].box].first = data[index].next;
168 if (data[index].next >= 0) {
169 data[data[index].next].prev = data[index].prev;
173 /// \brief Insert item into the box list.
174 void insert(int box, int index) {
175 if (boxes[box].first == -1) {
176 boxes[box].first = index;
177 data[index].next = data[index].prev = -1;
179 data[index].next = boxes[box].first;
180 data[boxes[box].first].prev = index;
181 data[index].prev = -1;
182 boxes[box].first = index;
184 data[index].box = box;
187 /// \brief Add a new box to the box list.
189 int min = boxes.back().min + boxes.back().size;
190 int bs = 2 * boxes.back().size;
191 boxes.push_back(RadixBox(min, bs));
194 /// \brief Move an item up into the proper box.
195 void bubble_up(int index) {
196 if (!lower(data[index].box, data[index].prio)) return;
198 int box = findUp(data[index].box, data[index].prio);
202 /// \brief Find up the proper box for the item with the given prio.
203 int findUp(int start, int pr) {
204 while (lower(start, pr)) {
205 if (++start == int(boxes.size())) {
212 /// \brief Move an item down into the proper box.
213 void bubble_down(int index) {
214 if (!upper(data[index].box, data[index].prio)) return;
216 int box = findDown(data[index].box, data[index].prio);
220 /// \brief Find up the proper box for the item with the given prio.
221 int findDown(int start, int pr) {
222 while (upper(start, pr)) {
223 if (--start < 0) throw UnderFlowPriorityError();
228 /// \brief Find the first not empty box.
231 while (boxes[first].first == -1) ++first;
235 /// \brief Gives back the minimal prio of the box.
236 int minValue(int box) {
237 int min = data[boxes[box].first].prio;
238 for (int k = boxes[box].first; k != -1; k = data[k].next) {
239 if (data[k].prio < min) min = data[k].prio;
244 /// \brief Rearrange the items of the heap and makes the
245 /// first box not empty.
247 int box = findFirst();
248 if (box == 0) return;
249 int min = minValue(box);
250 for (int i = 0; i <= box; ++i) {
252 min += boxes[i].size;
254 int curr = boxes[box].first, next;
256 next = data[curr].next;
262 void relocate_last(int index) {
263 if (index != int(data.size()) - 1) {
264 data[index] = data.back();
265 if (data[index].prev != -1) {
266 data[data[index].prev].next = index;
268 boxes[data[index].box].first = index;
270 if (data[index].next != -1) {
271 data[data[index].next].prev = index;
273 iim[data[index].item] = index;
280 /// \brief Insert an item into the heap with the given priority.
282 /// Adds \c i to the heap with priority \c p.
283 /// \param i The item to insert.
284 /// \param p The priority of the item.
285 void push(const Item &i, const Prio &p) {
288 data.push_back(RadixItem(i, p));
289 while (lower(boxes.size() - 1, p)) {
292 int box = findDown(boxes.size() - 1, p);
296 /// \brief Returns the item with minimum priority.
298 /// This method returns the item with minimum priority.
299 /// \pre The heap must be nonempty.
301 const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
302 return data[boxes[0].first].item;
305 /// \brief Returns the minimum priority.
307 /// It returns the minimum priority.
308 /// \pre The heap must be nonempty.
310 const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
311 return data[boxes[0].first].prio;
314 /// \brief Deletes the item with minimum priority.
316 /// This method deletes the item with minimum priority.
317 /// \pre The heap must be non-empty.
320 int index = boxes[0].first;
321 iim[data[index].item] = POST_HEAP;
323 relocate_last(index);
326 /// \brief Deletes \c i from the heap.
328 /// This method deletes item \c i from the heap, if \c i was
329 /// already stored in the heap.
330 /// \param i The item to erase.
331 void erase(const Item &i) {
335 relocate_last(index);
338 /// \brief Returns the priority of \c i.
340 /// This function returns the priority of item \c i.
341 /// \pre \c i must be in the heap.
342 /// \param i The item.
343 Prio operator[](const Item &i) const {
345 return data[idx].prio;
348 /// \brief \c i gets to the heap with priority \c p independently
349 /// if \c i was already there.
351 /// This method calls \ref push(\c i, \c p) if \c i is not stored
352 /// in the heap and sets the priority of \c i to \c p otherwise.
353 /// It may throw an \e UnderFlowPriorityException.
354 /// \param i The item.
355 /// \param p The priority.
356 void set(const Item &i, const Prio &p) {
361 else if( p >= data[idx].prio ) {
371 /// \brief Decreases the priority of \c i to \c p.
373 /// This method decreases the priority of item \c i to \c p.
374 /// \pre \c i must be stored in the heap with priority at least \c p, and
375 /// \c should be greater or equal to the last removed item's priority.
376 /// \param i The item.
377 /// \param p The priority.
378 void decrease(const Item &i, const Prio &p) {
384 /// \brief Increases the priority of \c i to \c p.
386 /// This method sets the priority of item \c i to \c p.
387 /// \pre \c i must be stored in the heap with priority at most \c p
388 /// \param i The item.
389 /// \param p The priority.
390 void increase(const Item &i, const Prio &p) {
396 /// \brief Returns if \c item is in, has already been in, or has
397 /// never been in the heap.
399 /// This method returns PRE_HEAP if \c item has never been in the
400 /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
401 /// otherwise. In the latter case it is possible that \c item will
402 /// get back to the heap again.
403 /// \param i The item.
404 state_enum state(const Item &i) const {
407 return state_enum(s);
410 /// \brief Sets the state of the \c item in the heap.
412 /// Sets the state of the \c item in the heap. It can be used to
413 /// manually clear the heap when it is important to achive the
414 /// better time complexity.
415 /// \param i The item.
416 /// \param st The state. It should not be \c IN_HEAP.
417 void state(const Item& i, state_enum st) {
421 if (state(i) == IN_HEAP) {
431 }; // class RadixHeap
435 #endif // LEMON_RADIX_HEAP_H