src/lemon/radix_heap.h
changeset 1331 7e93d3f0406d
parent 1205 a9a3354b01d4
child 1336 fd5fd79123fd
equal deleted inserted replaced
1:afb2b1bba40b 2:314ddbc27f5e
     1 /* -*- C++ -*-
     1 /* -*- C++ -*-
     2  * src/lemon/bin_heap.h - Part of LEMON, a generic C++ optimization library
     2  * src/lemon/radix_heap.h - Part of LEMON, a generic C++ optimization library
     3  *
     3  *
     4  * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     4  * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Combinatorial Optimization Research Group, EGRES).
     5  * (Egervary Combinatorial Optimization Research Group, EGRES).
     6  *
     6  *
     7  * Permission to use, modify and distribute this software is granted
     7  * Permission to use, modify and distribute this software is granted
    28 namespace lemon {
    28 namespace lemon {
    29 
    29 
    30   /// \addtogroup auxdat
    30   /// \addtogroup auxdat
    31   /// @{
    31   /// @{
    32 
    32 
    33   /// A Radix Heap implementation.
    33   /// \brief Exception thrown by RadixHeap.
    34   
    34   ///  
    35   ///\todo Please document...
    35   /// This Exception is thrown when a smaller priority
    36   ///
    36   /// is inserted into the \e RadixHeap then the last time erased.
    37   ///\sa BinHeap
    37   /// \see RadixHeap
    38   ///\sa Dijkstra
    38   /// \author Balazs Dezso
    39 
    39 
    40   class UnderFlowPriorityException : public RuntimeError {
    40   class UnderFlowPriorityError : public RuntimeError {
    41   public:
    41   public:
    42     virtual const char* exceptionName() const {
    42     virtual const char* exceptionName() const {
    43       return "lemon::UnderFlowPriorityException";
    43       return "lemon::UnderFlowPriorityError";
    44     }  
    44     }  
    45   };
    45   };
    46 
    46 
       
    47   /// \brief A Radix Heap implementation.
       
    48   ///
       
    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 
       
    55   /// item's priority.
       
    56   ///
       
    57   /// \param _Item Type of the items to be stored.  
       
    58   /// \param _ItemIntMap A read and writable Item int map, used internally
       
    59   /// to handle the cross references.
       
    60   ///
       
    61   /// \see BinHeap
       
    62   /// \see Dijkstra
       
    63   /// \author Balazs Dezso
       
    64 
    47   template <typename _Item, typename _ItemIntMap>
    65   template <typename _Item, typename _ItemIntMap>
    48   class RadixHeap {
    66   class RadixHeap {
    49 
    67 
    50   public:
    68   public:
    51     typedef _Item Item;
    69     typedef _Item Item;
    52     // FIXME: stl-ben nem ezt hivjak value_type -nak, hanem a kovetkezot...
       
    53     typedef int Prio;
    70     typedef int Prio;
    54     typedef _ItemIntMap ItemIntMap;
    71     typedef _ItemIntMap ItemIntMap;
    55 
    72 
    56     /**
    73     /// \brief Type to represent the items states.
    57      * Each Item element have a state associated to it. It may be "in heap",
    74     ///
    58      * "pre heap" or "post heap". The later two are indifferent from the
    75     /// Each Item element have a state associated to it. It may be "in heap",
    59      * heap's point of view, but may be useful to the user.
    76     /// "pre heap" or "post heap". The later two are indifferent from the
    60      *
    77     /// heap's point of view, but may be useful to the user.
    61      * The ItemIntMap _should_ be initialized in such way, that it maps
    78     ///
    62      * PRE_HEAP (-1) to any element to be put in the heap...
    79     /// The ItemIntMap _should_ be initialized in such way, that it maps
    63      */
    80     /// PRE_HEAP (-1) to any element to be put in the heap...
    64     ///\todo it is used nowhere
       
    65     ///
       
    66     enum state_enum {
    81     enum state_enum {
    67       IN_HEAP = 0,
    82       IN_HEAP = 0,
    68       PRE_HEAP = -1,
    83       PRE_HEAP = -1,
    69       POST_HEAP = -2
    84       POST_HEAP = -2
    70     };
    85     };
    89 
   104 
    90     ItemIntMap &iim;
   105     ItemIntMap &iim;
    91 
   106 
    92 
   107 
    93   public:
   108   public:
    94     ///\e
   109     /// \brief The constructor.
       
   110     ///
       
   111     /// The constructor.
       
   112     /// \param _iim 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.
    95     explicit RadixHeap(ItemIntMap &_iim) : iim(_iim) {
   115     explicit RadixHeap(ItemIntMap &_iim) : iim(_iim) {
    96       boxes.push_back(RadixBox(0, 1));
   116       boxes.push_back(RadixBox(0, 1));
    97       boxes.push_back(RadixBox(1, 1));
   117       boxes.push_back(RadixBox(1, 1));
    98     }
   118     }
    99 
   119 
   100     ///\e
   120     /// \brief The constructor.
       
   121     ///
       
   122     /// The constructor.
       
   123     ///
       
   124     /// \param _iim It should be given to the constructor, since it is used
       
   125     /// internally to handle the cross references. The value of the map
       
   126     /// should be PRE_HEAP (-1) for each element.
       
   127     ///
       
   128     /// \param capacity It determines the initial capacity of the heap. 
   101     RadixHeap(ItemIntMap &_iim, int capacity) : iim(_iim) {
   129     RadixHeap(ItemIntMap &_iim, int capacity) : iim(_iim) {
   102       boxes.push_back(RadixBox(0, 1));
   130       boxes.push_back(RadixBox(0, 1));
   103       boxes.push_back(RadixBox(1, 1));
   131       boxes.push_back(RadixBox(1, 1));
   104       while (upper(boxes.back(), capacity)) {
   132       while (upper(boxes.back(), capacity)) {
   105 	extend();
   133 	extend();
   106       }
   134       }
   107     }
   135     }
   108 
   136 
   109     ///\e
   137     /// The number of items stored in the heap.
       
   138     ///
       
   139     /// \brief Returns the number of items stored in the heap.
   110     int size() const { return data.size(); }
   140     int size() const { return data.size(); }
   111     ///\e
   141     /// \brief Checks if the heap stores no items.
       
   142     ///
       
   143     /// Returns \c true if and only if the heap stores no items.
   112     bool empty() const { return data.empty(); }
   144     bool empty() const { return data.empty(); }
   113 
   145 
   114   private:
   146   private:
   115 
   147 
   116     bool upper(int box, Prio prio) {
   148     bool upper(int box, Prio prio) {
   181     }
   213     }
   182 
   214 
   183     /// \brief Find up the proper box for the item with the given prio.
   215     /// \brief Find up the proper box for the item with the given prio.
   184     int findDown(int start, int prio) {
   216     int findDown(int start, int prio) {
   185       while (upper(start, prio)) {
   217       while (upper(start, prio)) {
   186 	if (--start < 0) throw UnderFlowPriorityException();
   218 	if (--start < 0) throw UnderFlowPriorityError();
   187       }
   219       }
   188       return start;
   220       return start;
   189     }
   221     }
   190 
   222 
   191     /// \brief Find the first not empty box.
   223     /// \brief Find the first not empty box.
   205     }
   237     }
   206 
   238 
   207     /// \brief Rearrange the items of the heap and makes the 
   239     /// \brief Rearrange the items of the heap and makes the 
   208     /// first box not empty.
   240     /// first box not empty.
   209     void moveDown() {
   241     void moveDown() {
   210       //      print(); printf("moveDown\n"); fflush(stdout);       
       
   211       int box = findFirst();
   242       int box = findFirst();
   212       if (box == 0) return;
   243       if (box == 0) return;
   213       int min = minValue(box);
   244       int min = minValue(box);
   214       for (int i = 0; i <= box; ++i) {
   245       for (int i = 0; i <= box; ++i) {
   215 	boxes[i].min = min;
   246 	boxes[i].min = min;
   239       data.pop_back();
   270       data.pop_back();
   240     }
   271     }
   241 
   272 
   242   public:
   273   public:
   243 
   274 
   244     ///\e
   275     /// \brief Insert an item into the heap with the given heap.
       
   276     ///    
       
   277     /// Adds \c i to the heap with priority \c p. 
       
   278     /// \param i The item to insert.
       
   279     /// \param p The priority of the item.
   245     void push(const Item &i, const Prio &p) {
   280     void push(const Item &i, const Prio &p) {
   246       fflush(stdout);
       
   247       int n = data.size();
   281       int n = data.size();
   248       iim.set(i, n);
   282       iim.set(i, n);
   249       data.push_back(RadixItem(i, p));
   283       data.push_back(RadixItem(i, p));
   250       while (lower(boxes.size() - 1, p)) {
   284       while (lower(boxes.size() - 1, p)) {
   251 	extend();
   285 	extend();
   252       }
   286       }
   253       int box = findDown(boxes.size() - 1, p);
   287       int box = findDown(boxes.size() - 1, p);
   254       insert(box, n);
   288       insert(box, n);
   255       //      printf("Push %d\n", p);
   289     }
   256       //print();
   290 
   257     }
   291     /// \brief Returns the item with minimum priority.
   258 
   292     ///
   259     ///\e
   293     /// This method returns the item with minimum priority.  
       
   294     /// \pre The heap must be nonempty.  
   260     Item top() const {
   295     Item top() const {
   261       //      print(); printf("top\n");  fflush(stdout);
       
   262       const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
   296       const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
   263       return data[boxes[0].first].item;
   297       return data[boxes[0].first].item;
   264       //      print(); printf("top_end\n");  fflush(stdout);
   298     }
   265     }
   299 
   266 
   300     /// \brief Returns the minimum priority.
   267     /// Returns the prio of the top element of the heap.
   301     ///
       
   302     /// It returns the minimum priority.
       
   303     /// \pre The heap must be nonempty.
   268     Prio prio() const {
   304     Prio prio() const {
   269       //      print(); printf("prio\n"); fflush(stdout);
       
   270       const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
   305       const_cast<RadixHeap<Item, ItemIntMap>*>(this)->moveDown();
   271       return data[boxes[0].first].prio;
   306       return data[boxes[0].first].prio;
   272      }
   307      }
   273 
   308 
   274     ///\e
   309     /// \brief Deletes the item with minimum priority.
       
   310     ///
       
   311     /// This method deletes the item with minimum priority.
       
   312     /// \pre The heap must be non-empty.  
   275     void pop() {
   313     void pop() {
   276       //      print(); printf("pop\n"); fflush(stdout);
       
   277       moveDown();
   314       moveDown();
   278       int index = boxes[0].first;
   315       int index = boxes[0].first;
   279       iim[data[index].item] = POST_HEAP;
   316       iim[data[index].item] = POST_HEAP;
   280       remove(index);
   317       remove(index);
   281       relocate_last(index);
   318       relocate_last(index);
   282       //      printf("Pop \n");
   319     }
   283       //print();
   320 
   284     }
   321     /// \brief Deletes \c i from the heap.
   285 
   322     ///
   286     ///\e
   323     /// This method deletes item \c i from the heap, if \c i was
       
   324     /// already stored in the heap.
       
   325     /// \param i The item to erase. 
   287     void erase(const Item &i) {
   326     void erase(const Item &i) {
   288       int index = iim[i];
   327       int index = iim[i];
   289       iim[i] = POST_HEAP;
   328       iim[i] = POST_HEAP;
   290       remove(index);
   329       remove(index);
   291       relocate_last(index);
   330       relocate_last(index);
   292    }
   331    }
   293 
   332 
   294     ///\e
   333     /// \brief Returns the priority of \c i.
       
   334     ///
       
   335     /// This function returns the priority of item \c i.  
       
   336     /// \pre \c i must be in the heap.
       
   337     /// \param i The item.
   295     Prio operator[](const Item &i) const {
   338     Prio operator[](const Item &i) const {
   296       int idx = iim[i];
   339       int idx = iim[i];
   297       return data[idx].prio;
   340       return data[idx].prio;
   298     }
   341     }
   299 
   342 
   300     ///\e
   343     /// \brief \c i gets to the heap with priority \c p independently 
       
   344     /// if \c i was already there.
       
   345     ///
       
   346     /// This method calls \ref push(\c i, \c p) if \c i is not stored
       
   347     /// in the heap and sets the priority of \c i to \c p otherwise.
       
   348     /// It may throw an \e UnderFlowPriorityException. 
       
   349     /// \param i The item.
       
   350     /// \param p The priority.
   301     void set(const Item &i, const Prio &p) {
   351     void set(const Item &i, const Prio &p) {
   302       int idx = iim[i];
   352       int idx = iim[i];
   303       if( idx < 0 ) {
   353       if( idx < 0 ) {
   304 	push(i, p);
   354 	push(i, p);
   305       }
   355       }
   310 	data[idx].prio = p;
   360 	data[idx].prio = p;
   311 	bubble_down(idx);
   361 	bubble_down(idx);
   312       }
   362       }
   313     }
   363     }
   314 
   364 
   315     ///\e
   365 
       
   366     /// \brief Decreases the priority of \c i to \c p.
       
   367     ///
       
   368     /// This method decreases the priority of item \c i to \c p.
       
   369     /// \pre \c i must be stored in the heap with priority at least \c p, and
       
   370     /// \c should be greater then the last removed item's priority.
       
   371     /// \param i The item.
       
   372     /// \param p The priority.
   316     void decrease(const Item &i, const Prio &p) {
   373     void decrease(const Item &i, const Prio &p) {
   317       //      print(); printf("decrease\n"); fflush(stdout);
       
   318       int idx = iim[i];
   374       int idx = iim[i];
   319       data[idx].prio = p;
   375       data[idx].prio = p;
   320       bubble_down(idx);
   376       bubble_down(idx);
   321     }
   377     }
   322 
   378 
   323     ///\e
   379     /// \brief Increases the priority of \c i to \c p.
       
   380     ///
       
   381     /// This method sets the priority of item \c i to \c p. 
       
   382     /// \pre \c i must be stored in the heap with priority at most \c
       
   383     /// p relative to \c Compare.
       
   384     /// \param i The item.
       
   385     /// \param p The priority.
   324     void increase(const Item &i, const Prio &p) {
   386     void increase(const Item &i, const Prio &p) {
   325       int idx = iim[i];
   387       int idx = iim[i];
   326       data[idx].prio = p;
   388       data[idx].prio = p;
   327       bubble_up(idx);
   389       bubble_up(idx);
   328     }
   390     }
   329 
   391 
   330     ///\e
   392     /// \brief Returns if \c item is in, has already been in, or has 
       
   393     /// never been in the heap.
       
   394     ///
       
   395     /// This method returns PRE_HEAP if \c item has never been in the
       
   396     /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
       
   397     /// otherwise. In the latter case it is possible that \c item will
       
   398     /// get back to the heap again.
       
   399     /// \param i The item.
   331     state_enum state(const Item &i) const {
   400     state_enum state(const Item &i) const {
   332       int s = iim[i];
   401       int s = iim[i];
   333       if( s >= 0 ) s = 0;
   402       if( s >= 0 ) s = 0;
   334       return state_enum(s);
   403       return state_enum(s);
   335     }
   404     }
   336 
   405 
   337 //     void print() const {
       
   338 //       for (int i = 0; i < boxes.size(); ++i) {
       
   339 // 	printf("(%d, %d) ", boxes[i].min, boxes[i].size);
       
   340 // 	for (int k = boxes[i].first; k != -1; k = data[k].next) {
       
   341 // 	  printf("%d ", data[k].prio);
       
   342 // 	}
       
   343 // 	printf("\n");
       
   344 //       }
       
   345 //       fflush(stdout);
       
   346 //     }
       
   347 
       
   348   }; // class RadixHeap
   406   }; // class RadixHeap
   349 
   407 
   350 
   408 
   351   ///@}
   409   ///@}
   352 
   410