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