COIN-OR::LEMON - Graph Library

source: lemon/lemon/bucket_heap.h @ 729:bb8c4cd57900

Last change on this file since 729:bb8c4cd57900 was 729:bb8c4cd57900, checked in by Balazs Dezso <deba@…>, 10 years ago

Simplified implementation of bucket heaps (#50)

File size: 16.1 KB
Line 
1/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library.
4 *
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
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.
12 *
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
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_BUCKET_HEAP_H
20#define LEMON_BUCKET_HEAP_H
21
22///\ingroup auxdat
23///\file
24///\brief Bucket Heap implementation.
25
26#include <vector>
27#include <utility>
28#include <functional>
29
30namespace lemon {
31
32  namespace _bucket_heap_bits {
33
34    template <bool minimize>
35    struct DirectionTraits {
36      static bool less(int left, int right) {
37        return left < right;
38      }
39      static void increase(int& value) {
40        ++value;
41      }
42    };
43
44    template <>
45    struct DirectionTraits<false> {
46      static bool less(int left, int right) {
47        return left > right;
48      }
49      static void increase(int& value) {
50        --value;
51      }
52    };
53
54  }
55
56  /// \ingroup auxdat
57  ///
58  /// \brief A Bucket Heap implementation.
59  ///
60  /// This class implements the \e bucket \e heap data structure. A \e heap
61  /// is a data structure for storing items with specified values called \e
62  /// priorities in such a way that finding the item with minimum priority is
63  /// efficient. The bucket heap is very simple implementation, it can store
64  /// only integer priorities and it stores for each priority in the
65  /// \f$ [0..C) \f$ range a list of items. So it should be used only when
66  /// the priorities are small. It is not intended to use as dijkstra heap.
67  ///
68  /// \param _ItemIntMap A read and writable Item int map, used internally
69  /// to handle the cross references.
70  /// \param minimize If the given parameter is true then the heap gives back
71  /// the lowest priority.
72  template <typename _ItemIntMap, bool minimize = true>
73  class BucketHeap {
74
75  public:
76    /// \e
77    typedef typename _ItemIntMap::Key Item;
78    /// \e
79    typedef int Prio;
80    /// \e
81    typedef std::pair<Item, Prio> Pair;
82    /// \e
83    typedef _ItemIntMap ItemIntMap;
84
85  private:
86
87    typedef _bucket_heap_bits::DirectionTraits<minimize> Direction;
88
89  public:
90
91    /// \brief Type to represent the items states.
92    ///
93    /// Each Item element have a state associated to it. It may be "in heap",
94    /// "pre heap" or "post heap". The latter two are indifferent from the
95    /// heap's point of view, but may be useful to the user.
96    ///
97    /// The ItemIntMap \e should be initialized in such way that it maps
98    /// PRE_HEAP (-1) to any element to be put in the heap...
99    enum State {
100      IN_HEAP = 0,
101      PRE_HEAP = -1,
102      POST_HEAP = -2
103    };
104
105  public:
106    /// \brief The constructor.
107    ///
108    /// The constructor.
109    /// \param _index should be given to the constructor, since it is used
110    /// internally to handle the cross references. The value of the map
111    /// should be PRE_HEAP (-1) for each element.
112    explicit BucketHeap(ItemIntMap &_index) : index(_index), minimal(0) {}
113
114    /// The number of items stored in the heap.
115    ///
116    /// \brief Returns the number of items stored in the heap.
117    int size() const { return data.size(); }
118
119    /// \brief Checks if the heap stores no items.
120    ///
121    /// Returns \c true if and only if the heap stores no items.
122    bool empty() const { return data.empty(); }
123
124    /// \brief Make empty this heap.
125    ///
126    /// Make empty this heap. It does not change the cross reference
127    /// map.  If you want to reuse a heap what is not surely empty you
128    /// should first clear the heap and after that you should set the
129    /// cross reference map for each item to \c PRE_HEAP.
130    void clear() {
131      data.clear(); first.clear(); minimal = 0;
132    }
133
134  private:
135
136    void relocate_last(int idx) {
137      if (idx + 1 < int(data.size())) {
138        data[idx] = data.back();
139        if (data[idx].prev != -1) {
140          data[data[idx].prev].next = idx;
141        } else {
142          first[data[idx].value] = idx;
143        }
144        if (data[idx].next != -1) {
145          data[data[idx].next].prev = idx;
146        }
147        index[data[idx].item] = idx;
148      }
149      data.pop_back();
150    }
151
152    void unlace(int idx) {
153      if (data[idx].prev != -1) {
154        data[data[idx].prev].next = data[idx].next;
155      } else {
156        first[data[idx].value] = data[idx].next;
157      }
158      if (data[idx].next != -1) {
159        data[data[idx].next].prev = data[idx].prev;
160      }
161    }
162
163    void lace(int idx) {
164      if (int(first.size()) <= data[idx].value) {
165        first.resize(data[idx].value + 1, -1);
166      }
167      data[idx].next = first[data[idx].value];
168      if (data[idx].next != -1) {
169        data[data[idx].next].prev = idx;
170      }
171      first[data[idx].value] = idx;
172      data[idx].prev = -1;
173    }
174
175  public:
176    /// \brief Insert a pair of item and priority into the heap.
177    ///
178    /// Adds \c p.first to the heap with priority \c p.second.
179    /// \param p The pair to insert.
180    void push(const Pair& p) {
181      push(p.first, p.second);
182    }
183
184    /// \brief Insert an item into the heap with the given priority.
185    ///
186    /// Adds \c i to the heap with priority \c p.
187    /// \param i The item to insert.
188    /// \param p The priority of the item.
189    void push(const Item &i, const Prio &p) {
190      int idx = data.size();
191      index[i] = idx;
192      data.push_back(BucketItem(i, p));
193      lace(idx);
194      if (Direction::less(p, minimal)) {
195        minimal = p;
196      }
197    }
198
199    /// \brief Returns the item with minimum priority.
200    ///
201    /// This method returns the item with minimum priority.
202    /// \pre The heap must be nonempty.
203    Item top() const {
204      while (first[minimal] == -1) {
205        Direction::increase(minimal);
206      }
207      return data[first[minimal]].item;
208    }
209
210    /// \brief Returns the minimum priority.
211    ///
212    /// It returns the minimum priority.
213    /// \pre The heap must be nonempty.
214    Prio prio() const {
215      while (first[minimal] == -1) {
216        Direction::increase(minimal);
217      }
218      return minimal;
219    }
220
221    /// \brief Deletes the item with minimum priority.
222    ///
223    /// This method deletes the item with minimum priority from the heap.
224    /// \pre The heap must be non-empty.
225    void pop() {
226      while (first[minimal] == -1) {
227        Direction::increase(minimal);
228      }
229      int idx = first[minimal];
230      index[data[idx].item] = -2;
231      unlace(idx);
232      relocate_last(idx);
233    }
234
235    /// \brief Deletes \c i from the heap.
236    ///
237    /// This method deletes item \c i from the heap, if \c i was
238    /// already stored in the heap.
239    /// \param i The item to erase.
240    void erase(const Item &i) {
241      int idx = index[i];
242      index[data[idx].item] = -2;
243      unlace(idx);
244      relocate_last(idx);
245    }
246
247
248    /// \brief Returns the priority of \c i.
249    ///
250    /// This function returns the priority of item \c i.
251    /// \pre \c i must be in the heap.
252    /// \param i The item.
253    Prio operator[](const Item &i) const {
254      int idx = index[i];
255      return data[idx].value;
256    }
257
258    /// \brief \c i gets to the heap with priority \c p independently
259    /// if \c i was already there.
260    ///
261    /// This method calls \ref push(\c i, \c p) if \c i is not stored
262    /// in the heap and sets the priority of \c i to \c p otherwise.
263    /// \param i The item.
264    /// \param p The priority.
265    void set(const Item &i, const Prio &p) {
266      int idx = index[i];
267      if (idx < 0) {
268        push(i, p);
269      } else if (Direction::less(p, data[idx].value)) {
270        decrease(i, p);
271      } else {
272        increase(i, p);
273      }
274    }
275
276    /// \brief Decreases the priority of \c i to \c p.
277    ///
278    /// This method decreases the priority of item \c i to \c p.
279    /// \pre \c i must be stored in the heap with priority at least \c
280    /// p relative to \c Compare.
281    /// \param i The item.
282    /// \param p The priority.
283    void decrease(const Item &i, const Prio &p) {
284      int idx = index[i];
285      unlace(idx);
286      data[idx].value = p;
287      if (Direction::less(p, minimal)) {
288        minimal = p;
289      }
290      lace(idx);
291    }
292
293    /// \brief Increases the priority of \c i to \c p.
294    ///
295    /// This method sets the priority of item \c i to \c p.
296    /// \pre \c i must be stored in the heap with priority at most \c
297    /// p relative to \c Compare.
298    /// \param i The item.
299    /// \param p The priority.
300    void increase(const Item &i, const Prio &p) {
301      int idx = index[i];
302      unlace(idx);
303      data[idx].value = p;
304      lace(idx);
305    }
306
307    /// \brief Returns if \c item is in, has already been in, or has
308    /// never been in the heap.
309    ///
310    /// This method returns PRE_HEAP if \c item has never been in the
311    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
312    /// otherwise. In the latter case it is possible that \c item will
313    /// get back to the heap again.
314    /// \param i The item.
315    State state(const Item &i) const {
316      int idx = index[i];
317      if (idx >= 0) idx = 0;
318      return State(idx);
319    }
320
321    /// \brief Sets the state of the \c item in the heap.
322    ///
323    /// Sets the state of the \c item in the heap. It can be used to
324    /// manually clear the heap when it is important to achive the
325    /// better time complexity.
326    /// \param i The item.
327    /// \param st The state. It should not be \c IN_HEAP.
328    void state(const Item& i, State st) {
329      switch (st) {
330      case POST_HEAP:
331      case PRE_HEAP:
332        if (state(i) == IN_HEAP) {
333          erase(i);
334        }
335        index[i] = st;
336        break;
337      case IN_HEAP:
338        break;
339      }
340    }
341
342  private:
343
344    struct BucketItem {
345      BucketItem(const Item& _item, int _value)
346        : item(_item), value(_value) {}
347
348      Item item;
349      int value;
350
351      int prev, next;
352    };
353
354    ItemIntMap& index;
355    std::vector<int> first;
356    std::vector<BucketItem> data;
357    mutable int minimal;
358
359  }; // class BucketHeap
360
361  /// \ingroup auxdat
362  ///
363  /// \brief A Simplified Bucket Heap implementation.
364  ///
365  /// This class implements a simplified \e bucket \e heap data
366  /// structure.  It does not provide some functionality but it faster
367  /// and simplier data structure than the BucketHeap. The main
368  /// difference is that the BucketHeap stores for every key a double
369  /// linked list while this class stores just simple lists. In the
370  /// other way it does not support erasing each elements just the
371  /// minimal and it does not supports key increasing, decreasing.
372  ///
373  /// \param _ItemIntMap A read and writable Item int map, used internally
374  /// to handle the cross references.
375  /// \param minimize If the given parameter is true then the heap gives back
376  /// the lowest priority.
377  ///
378  /// \sa BucketHeap
379  template <typename _ItemIntMap, bool minimize = true >
380  class SimpleBucketHeap {
381
382  public:
383    typedef typename _ItemIntMap::Key Item;
384    typedef int Prio;
385    typedef std::pair<Item, Prio> Pair;
386    typedef _ItemIntMap ItemIntMap;
387
388  private:
389
390    typedef _bucket_heap_bits::DirectionTraits<minimize> Direction;
391
392  public:
393
394    /// \brief Type to represent the items states.
395    ///
396    /// Each Item element have a state associated to it. It may be "in heap",
397    /// "pre heap" or "post heap". The latter two are indifferent from the
398    /// heap's point of view, but may be useful to the user.
399    ///
400    /// The ItemIntMap \e should be initialized in such way that it maps
401    /// PRE_HEAP (-1) to any element to be put in the heap...
402    enum State {
403      IN_HEAP = 0,
404      PRE_HEAP = -1,
405      POST_HEAP = -2
406    };
407
408  public:
409
410    /// \brief The constructor.
411    ///
412    /// The constructor.
413    /// \param _index should be given to the constructor, since it is used
414    /// internally to handle the cross references. The value of the map
415    /// should be PRE_HEAP (-1) for each element.
416    explicit SimpleBucketHeap(ItemIntMap &_index)
417      : index(_index), free(-1), num(0), minimal(0) {}
418
419    /// \brief Returns the number of items stored in the heap.
420    ///
421    /// The number of items stored in the heap.
422    int size() const { return num; }
423
424    /// \brief Checks if the heap stores no items.
425    ///
426    /// Returns \c true if and only if the heap stores no items.
427    bool empty() const { return num == 0; }
428
429    /// \brief Make empty this heap.
430    ///
431    /// Make empty this heap. It does not change the cross reference
432    /// map.  If you want to reuse a heap what is not surely empty you
433    /// should first clear the heap and after that you should set the
434    /// cross reference map for each item to \c PRE_HEAP.
435    void clear() {
436      data.clear(); first.clear(); free = -1; num = 0; minimal = 0;
437    }
438
439    /// \brief Insert a pair of item and priority into the heap.
440    ///
441    /// Adds \c p.first to the heap with priority \c p.second.
442    /// \param p The pair to insert.
443    void push(const Pair& p) {
444      push(p.first, p.second);
445    }
446
447    /// \brief Insert an item into the heap with the given priority.
448    ///
449    /// Adds \c i to the heap with priority \c p.
450    /// \param i The item to insert.
451    /// \param p The priority of the item.
452    void push(const Item &i, const Prio &p) {
453      int idx;
454      if (free == -1) {
455        idx = data.size();
456        data.push_back(BucketItem(i));
457      } else {
458        idx = free;
459        free = data[idx].next;
460        data[idx].item = i;
461      }
462      index[i] = idx;
463      if (p >= int(first.size())) first.resize(p + 1, -1);
464      data[idx].next = first[p];
465      first[p] = idx;
466      if (Direction::less(p, minimal)) {
467        minimal = p;
468      }
469      ++num;
470    }
471
472    /// \brief Returns the item with minimum priority.
473    ///
474    /// This method returns the item with minimum priority.
475    /// \pre The heap must be nonempty.
476    Item top() const {
477      while (first[minimal] == -1) {
478        Direction::increase(minimal);
479      }
480      return data[first[minimal]].item;
481    }
482
483    /// \brief Returns the minimum priority.
484    ///
485    /// It returns the minimum priority.
486    /// \pre The heap must be nonempty.
487    Prio prio() const {
488      while (first[minimal] == -1) {
489        Direction::increase(minimal);
490      }
491      return minimal;
492    }
493
494    /// \brief Deletes the item with minimum priority.
495    ///
496    /// This method deletes the item with minimum priority from the heap.
497    /// \pre The heap must be non-empty.
498    void pop() {
499      while (first[minimal] == -1) {
500        Direction::increase(minimal);
501      }
502      int idx = first[minimal];
503      index[data[idx].item] = -2;
504      first[minimal] = data[idx].next;
505      data[idx].next = free;
506      free = idx;
507      --num;
508    }
509
510    /// \brief Returns the priority of \c i.
511    ///
512    /// This function returns the priority of item \c i.
513    /// \warning This operator is not a constant time function
514    /// because it scans the whole data structure to find the proper
515    /// value.
516    /// \pre \c i must be in the heap.
517    /// \param i The item.
518    Prio operator[](const Item &i) const {
519      for (int k = 0; k < first.size(); ++k) {
520        int idx = first[k];
521        while (idx != -1) {
522          if (data[idx].item == i) {
523            return k;
524          }
525          idx = data[idx].next;
526        }
527      }
528      return -1;
529    }
530
531    /// \brief Returns if \c item is in, has already been in, or has
532    /// never been in the heap.
533    ///
534    /// This method returns PRE_HEAP if \c item has never been in the
535    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
536    /// otherwise. In the latter case it is possible that \c item will
537    /// get back to the heap again.
538    /// \param i The item.
539    State state(const Item &i) const {
540      int idx = index[i];
541      if (idx >= 0) idx = 0;
542      return State(idx);
543    }
544
545  private:
546
547    struct BucketItem {
548      BucketItem(const Item& _item)
549        : item(_item) {}
550
551      Item item;
552      int next;
553    };
554
555    ItemIntMap& index;
556    std::vector<int> first;
557    std::vector<BucketItem> data;
558    int free, num;
559    mutable int minimal;
560
561  }; // class SimpleBucketHeap
562
563}
564
565#endif
Note: See TracBrowser for help on using the repository browser.