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