lemon/linear_heap.h
author alpar
Mon, 05 Dec 2005 17:03:31 +0000
changeset 1847 7cbc12e42482
parent 1758 4bfe670710e0
child 1875 98698b69a902
permissions -rw-r--r--
- Changed and improved Timer interface
- several new member functions
- reset() -> restart() renaming
- TimeReport: a Timer that prints a report on destruction.
- counter.h: a tool to measure the number of streps of algorithms.
- New documentation module for time measuring and counting.
     1 /* -*- C++ -*-
     2  * lemon/linear_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_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   private:
   287 
   288     struct LinearItem {
   289       LinearItem(const Item& _item, int _value) 
   290 	: item(_item), value(_value) {}
   291 
   292       Item item;
   293       int value;
   294 
   295       int prev, next;
   296     };
   297 
   298     ItemIntMap& index;
   299     std::vector<int> first;
   300     std::vector<LinearItem> data;
   301     mutable int minimal;
   302 
   303   }; // class LinearHeap
   304 
   305 
   306   template <typename _Item, typename _ItemIntMap>
   307   class LinearHeap<_Item, _ItemIntMap, false> {
   308 
   309   public:
   310     typedef _Item Item;
   311     typedef int Prio;
   312     typedef std::pair<Item, Prio> Pair;
   313     typedef _ItemIntMap ItemIntMap;
   314 
   315     enum state_enum {
   316       IN_HEAP = 0,
   317       PRE_HEAP = -1,
   318       POST_HEAP = -2
   319     };
   320 
   321   public:
   322 
   323     explicit LinearHeap(ItemIntMap &_index) : index(_index), maximal(-1) {}
   324 
   325     int size() const { return data.size(); }
   326     bool empty() const { return data.empty(); }
   327 
   328     void clear() { 
   329       for (int i = 0; i < (int)data.size(); ++i) {
   330 	index[data[i].item] = -2;
   331       }
   332       data.clear(); first.clear(); maximal = -1; 
   333     }
   334 
   335   private:
   336 
   337     void relocate_last(int idx) {
   338       if (idx + 1 != (int)data.size()) {
   339 	data[idx] = data.back();
   340 	if (data[idx].prev != -1) {
   341 	  data[data[idx].prev].next = idx;
   342 	} else {
   343 	  first[data[idx].value] = idx;
   344 	}
   345 	if (data[idx].next != -1) {
   346 	  data[data[idx].next].prev = idx;
   347 	}
   348 	index[data[idx].item] = idx;
   349       }
   350       data.pop_back();
   351     }
   352 
   353     void unlace(int idx) {
   354       if (data[idx].prev != -1) {
   355 	data[data[idx].prev].next = data[idx].next;
   356       } else {
   357 	first[data[idx].value] = data[idx].next;
   358       }
   359       if (data[idx].next != -1) {
   360 	data[data[idx].next].prev = data[idx].prev;
   361       }
   362     }
   363 
   364     void lace(int idx) {
   365       if ((int)first.size() <= data[idx].value) {
   366 	first.resize(data[idx].value + 1, -1);
   367       }
   368       data[idx].next = first[data[idx].value];
   369       if (data[idx].next != -1) {
   370 	data[data[idx].next].prev = idx;
   371       }
   372       first[data[idx].value] = idx;
   373       data[idx].prev = -1;
   374     }
   375 
   376   public:
   377 
   378     void push(const Pair& p) {
   379       push(p.first, p.second);
   380     }
   381 
   382     void push(const Item &i, const Prio &p) { 
   383       int idx = data.size();
   384       index[i] = idx;
   385       data.push_back(LinearItem(i, p));
   386       lace(idx);
   387       if (data[idx].value > maximal) {
   388 	maximal = data[idx].value;
   389       }
   390     }
   391 
   392     Item top() const {
   393       while (first[maximal] == -1) {
   394 	--maximal;
   395       }
   396       return data[first[maximal]].item;
   397     }
   398 
   399     Prio prio() const {
   400       while (first[maximal] == -1) {
   401 	--maximal;
   402       }
   403       return maximal;
   404     }
   405 
   406     void pop() {
   407       while (first[maximal] == -1) {
   408 	--maximal;
   409       }
   410       int idx = first[maximal];
   411       index[data[idx].item] = -2;
   412       unlace(idx);
   413       relocate_last(idx);
   414     }
   415 
   416     void erase(const Item &i) {
   417       int idx = index[i];
   418       index[data[idx].item] = -2;
   419       unlace(idx);
   420       relocate_last(idx);
   421     }
   422 
   423     Prio operator[](const Item &i) const {
   424       int idx = index[i];
   425       return data[idx].value;
   426     }
   427 
   428     void set(const Item &i, const Prio &p) {
   429       int idx = index[i];
   430       if (idx < 0) {
   431 	push(i,p);
   432       } else if (p > data[idx].value) {
   433 	decrease(i, p);
   434       } else {
   435 	increase(i, p);
   436       }
   437     }
   438 
   439     void decrease(const Item &i, const Prio &p) {
   440       int idx = index[i];
   441       unlace(idx);
   442       data[idx].value = p;
   443       if (p > maximal) {
   444 	maximal = p;
   445       }
   446       lace(idx);
   447     }
   448     
   449     void increase(const Item &i, const Prio &p) {
   450       int idx = index[i];
   451       unlace(idx);
   452       data[idx].value = p;
   453       lace(idx);
   454     }
   455 
   456     state_enum state(const Item &i) const {
   457       int idx = index[i];
   458       if (idx >= 0) idx = 0;
   459       return state_enum(idx);
   460     }
   461 
   462   private:
   463 
   464     struct LinearItem {
   465       LinearItem(const Item& _item, int _value) 
   466 	: item(_item), value(_value) {}
   467 
   468       Item item;
   469       int value;
   470 
   471       int prev, next;
   472     };
   473 
   474     ItemIntMap& index;
   475     std::vector<int> first;
   476     std::vector<LinearItem> data;
   477     mutable int maximal;
   478 
   479   }; // class LinearHeap
   480 
   481 }
   482   
   483 #endif