lemon/bucket_heap.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2089 fce8db723736
child 2263 9273fe7d850c
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

The tests have been modified to the current implementation
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     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 
    30 namespace lemon {
    31 
    32   /// \ingroup auxdat
    33   ///
    34   /// \brief A Bucket Heap implementation.
    35   ///
    36   /// This class implements the \e bucket \e heap data structure. A \e heap
    37   /// is a data structure for storing items with specified values called \e
    38   /// priorities in such a way that finding the item with minimum priority is
    39   /// efficient. The bucket heap is very simple implementation, it can store
    40   /// only integer priorities and it stores for each priority in the 
    41   /// \f$ [0..C) \f$ range a list of items. So it should be used only when 
    42   /// the priorities are small. It is not intended to use as dijkstra heap.
    43   ///
    44   /// \param _Item Type of the items to be stored.  
    45   /// \param _ItemIntMap A read and writable Item int map, used internally
    46   /// to handle the cross references.
    47   /// \param minimize If the given parameter is true then the heap gives back
    48   /// the lowest priority. 
    49   template <typename _Item, typename _ItemIntMap, bool minimize = true >
    50   class BucketHeap {
    51 
    52   public:
    53     typedef _Item Item;
    54     typedef int Prio;
    55     typedef std::pair<Item, Prio> Pair;
    56     typedef _ItemIntMap ItemIntMap;
    57 
    58     /// \brief Type to represent the items states.
    59     ///
    60     /// Each Item element have a state associated to it. It may be "in heap",
    61     /// "pre heap" or "post heap". The latter two are indifferent from the
    62     /// heap's point of view, but may be useful to the user.
    63     ///
    64     /// The ItemIntMap \e should be initialized in such way that it maps
    65     /// PRE_HEAP (-1) to any element to be put in the heap...
    66     enum state_enum {
    67       IN_HEAP = 0,
    68       PRE_HEAP = -1,
    69       POST_HEAP = -2
    70     };
    71 
    72   public:
    73     /// \brief The constructor.
    74     ///
    75     /// The constructor.
    76     /// \param _index should be given to the constructor, since it is used
    77     /// internally to handle the cross references. The value of the map
    78     /// should be PRE_HEAP (-1) for each element.
    79     explicit BucketHeap(ItemIntMap &_index) : index(_index), minimal(0) {}
    80     
    81     /// The number of items stored in the heap.
    82     ///
    83     /// \brief Returns the number of items stored in the heap.
    84     int size() const { return data.size(); }
    85     
    86     /// \brief Checks if the heap stores no items.
    87     ///
    88     /// Returns \c true if and only if the heap stores no items.
    89     bool empty() const { return data.empty(); }
    90 
    91     /// \brief Make empty this heap.
    92     /// 
    93     /// Make empty this heap. It does not change the cross reference
    94     /// map.  If you want to reuse a heap what is not surely empty you
    95     /// should first clear the heap and after that you should set the
    96     /// cross reference map for each item to \c PRE_HEAP.
    97     void clear() { 
    98       data.clear(); first.clear(); minimal = 0;
    99     }
   100 
   101   private:
   102 
   103     void relocate_last(int idx) {
   104       if (idx + 1 < (int)data.size()) {
   105 	data[idx] = data.back();
   106 	if (data[idx].prev != -1) {
   107 	  data[data[idx].prev].next = idx;
   108 	} else {
   109 	  first[data[idx].value] = idx;
   110 	}
   111 	if (data[idx].next != -1) {
   112 	  data[data[idx].next].prev = idx;
   113 	}
   114 	index[data[idx].item] = idx;
   115       }
   116       data.pop_back();
   117     }
   118 
   119     void unlace(int idx) {
   120       if (data[idx].prev != -1) {
   121 	data[data[idx].prev].next = data[idx].next;
   122       } else {
   123 	first[data[idx].value] = data[idx].next;
   124       }
   125       if (data[idx].next != -1) {
   126 	data[data[idx].next].prev = data[idx].prev;
   127       }
   128     }
   129 
   130     void lace(int idx) {
   131       if ((int)first.size() <= data[idx].value) {
   132 	first.resize(data[idx].value + 1, -1);
   133       }
   134       data[idx].next = first[data[idx].value];
   135       if (data[idx].next != -1) {
   136 	data[data[idx].next].prev = idx;
   137       }
   138       first[data[idx].value] = idx;
   139       data[idx].prev = -1;
   140     }
   141 
   142   public:
   143     /// \brief Insert a pair of item and priority into the heap.
   144     ///
   145     /// Adds \c p.first to the heap with priority \c p.second.
   146     /// \param p The pair to insert.
   147     void push(const Pair& p) {
   148       push(p.first, p.second);
   149     }
   150 
   151     /// \brief Insert an item into the heap with the given priority.
   152     ///    
   153     /// Adds \c i to the heap with priority \c p. 
   154     /// \param i The item to insert.
   155     /// \param p The priority of the item.
   156     void push(const Item &i, const Prio &p) { 
   157       int idx = data.size();
   158       index[i] = idx;
   159       data.push_back(BucketItem(i, p));
   160       lace(idx);
   161       if (p < minimal) {
   162 	minimal = p;
   163       }
   164     }
   165 
   166     /// \brief Returns the item with minimum priority.
   167     ///
   168     /// This method returns the item with minimum priority.
   169     /// \pre The heap must be nonempty.  
   170     Item top() const {
   171       while (first[minimal] == -1) {
   172 	++minimal;
   173       }
   174       return data[first[minimal]].item;
   175     }
   176 
   177     /// \brief Returns the minimum priority.
   178     ///
   179     /// It returns the minimum priority.
   180     /// \pre The heap must be nonempty.
   181     Prio prio() const {
   182       while (first[minimal] == -1) {
   183 	++minimal;
   184       }
   185       return minimal;
   186     }
   187 
   188     /// \brief Deletes the item with minimum priority.
   189     ///
   190     /// This method deletes the item with minimum priority from the heap.  
   191     /// \pre The heap must be non-empty.  
   192     void pop() {
   193       while (first[minimal] == -1) {
   194 	++minimal;
   195       }
   196       int idx = first[minimal];
   197       index[data[idx].item] = -2;
   198       unlace(idx);
   199       relocate_last(idx);
   200     }
   201 
   202     /// \brief Deletes \c i from the heap.
   203     ///
   204     /// This method deletes item \c i from the heap, if \c i was
   205     /// already stored in the heap.
   206     /// \param i The item to erase. 
   207     void erase(const Item &i) {
   208       int idx = index[i];
   209       index[data[idx].item] = -2;
   210       unlace(idx);
   211       relocate_last(idx);
   212     }
   213 
   214     
   215     /// \brief Returns the priority of \c i.
   216     ///
   217     /// This function returns the priority of item \c i.  
   218     /// \pre \c i must be in the heap.
   219     /// \param i The item.
   220     Prio operator[](const Item &i) const {
   221       int idx = index[i];
   222       return data[idx].value;
   223     }
   224 
   225     /// \brief \c i gets to the heap with priority \c p independently 
   226     /// if \c i was already there.
   227     ///
   228     /// This method calls \ref push(\c i, \c p) if \c i is not stored
   229     /// in the heap and sets the priority of \c i to \c p otherwise.
   230     /// \param i The item.
   231     /// \param p The priority.
   232     void set(const Item &i, const Prio &p) {
   233       int idx = index[i];
   234       if (idx < 0) {
   235 	push(i,p);
   236       } else if (p > data[idx].value) {
   237 	increase(i, p);
   238       } else {
   239 	decrease(i, p);
   240       }
   241     }
   242 
   243     /// \brief Decreases the priority of \c i to \c p.
   244     ///
   245     /// This method decreases the priority of item \c i to \c p.
   246     /// \pre \c i must be stored in the heap with priority at least \c
   247     /// p relative to \c Compare.
   248     /// \param i The item.
   249     /// \param p The priority.
   250     void decrease(const Item &i, const Prio &p) {
   251       int idx = index[i];
   252       unlace(idx);
   253       data[idx].value = p;
   254       if (p < minimal) {
   255 	minimal = p;
   256       }
   257       lace(idx);
   258     }
   259     
   260     /// \brief Increases the priority of \c i to \c p.
   261     ///
   262     /// This method sets the priority of item \c i to \c p. 
   263     /// \pre \c i must be stored in the heap with priority at most \c
   264     /// p relative to \c Compare.
   265     /// \param i The item.
   266     /// \param p The priority.
   267     void increase(const Item &i, const Prio &p) {
   268       int idx = index[i];
   269       unlace(idx);
   270       data[idx].value = p;
   271       lace(idx);
   272     }
   273 
   274     /// \brief Returns if \c item is in, has already been in, or has 
   275     /// never been in the heap.
   276     ///
   277     /// This method returns PRE_HEAP if \c item has never been in the
   278     /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
   279     /// otherwise. In the latter case it is possible that \c item will
   280     /// get back to the heap again.
   281     /// \param i The item.
   282     state_enum state(const Item &i) const {
   283       int idx = index[i];
   284       if (idx >= 0) idx = 0;
   285       return state_enum(idx);
   286     }
   287 
   288     /// \brief Sets the state of the \c item in the heap.
   289     ///
   290     /// Sets the state of the \c item in the heap. It can be used to
   291     /// manually clear the heap when it is important to achive the
   292     /// better time complexity.
   293     /// \param i The item.
   294     /// \param st The state. It should not be \c IN_HEAP. 
   295     void state(const Item& i, state_enum st) {
   296       switch (st) {
   297       case POST_HEAP:
   298       case PRE_HEAP:
   299         if (state(i) == IN_HEAP) {
   300           erase(i);
   301         }
   302         index[i] = st;
   303         break;
   304       case IN_HEAP:
   305         break;
   306       }
   307     }
   308 
   309   private:
   310 
   311     struct BucketItem {
   312       BucketItem(const Item& _item, int _value) 
   313 	: item(_item), value(_value) {}
   314 
   315       Item item;
   316       int value;
   317 
   318       int prev, next;
   319     };
   320 
   321     ItemIntMap& index;
   322     std::vector<int> first;
   323     std::vector<BucketItem> data;
   324     mutable int minimal;
   325 
   326   }; // class BucketHeap
   327 
   328 
   329   template <typename _Item, typename _ItemIntMap>
   330   class BucketHeap<_Item, _ItemIntMap, false> {
   331 
   332   public:
   333     typedef _Item Item;
   334     typedef int Prio;
   335     typedef std::pair<Item, Prio> Pair;
   336     typedef _ItemIntMap ItemIntMap;
   337 
   338     enum state_enum {
   339       IN_HEAP = 0,
   340       PRE_HEAP = -1,
   341       POST_HEAP = -2
   342     };
   343 
   344   public:
   345 
   346     explicit BucketHeap(ItemIntMap &_index) : index(_index), maximal(-1) {}
   347 
   348     int size() const { return data.size(); }
   349     bool empty() const { return data.empty(); }
   350 
   351     void clear() { 
   352       data.clear(); first.clear(); maximal = -1; 
   353     }
   354 
   355   private:
   356 
   357     void relocate_last(int idx) {
   358       if (idx + 1 != (int)data.size()) {
   359 	data[idx] = data.back();
   360 	if (data[idx].prev != -1) {
   361 	  data[data[idx].prev].next = idx;
   362 	} else {
   363 	  first[data[idx].value] = idx;
   364 	}
   365 	if (data[idx].next != -1) {
   366 	  data[data[idx].next].prev = idx;
   367 	}
   368 	index[data[idx].item] = idx;
   369       }
   370       data.pop_back();
   371     }
   372 
   373     void unlace(int idx) {
   374       if (data[idx].prev != -1) {
   375 	data[data[idx].prev].next = data[idx].next;
   376       } else {
   377 	first[data[idx].value] = data[idx].next;
   378       }
   379       if (data[idx].next != -1) {
   380 	data[data[idx].next].prev = data[idx].prev;
   381       }
   382     }
   383 
   384     void lace(int idx) {
   385       if ((int)first.size() <= data[idx].value) {
   386 	first.resize(data[idx].value + 1, -1);
   387       }
   388       data[idx].next = first[data[idx].value];
   389       if (data[idx].next != -1) {
   390 	data[data[idx].next].prev = idx;
   391       }
   392       first[data[idx].value] = idx;
   393       data[idx].prev = -1;
   394     }
   395 
   396   public:
   397 
   398     void push(const Pair& p) {
   399       push(p.first, p.second);
   400     }
   401 
   402     void push(const Item &i, const Prio &p) { 
   403       int idx = data.size();
   404       index[i] = idx;
   405       data.push_back(BucketItem(i, p));
   406       lace(idx);
   407       if (data[idx].value > maximal) {
   408 	maximal = data[idx].value;
   409       }
   410     }
   411 
   412     Item top() const {
   413       while (first[maximal] == -1) {
   414 	--maximal;
   415       }
   416       return data[first[maximal]].item;
   417     }
   418 
   419     Prio prio() const {
   420       while (first[maximal] == -1) {
   421 	--maximal;
   422       }
   423       return maximal;
   424     }
   425 
   426     void pop() {
   427       while (first[maximal] == -1) {
   428 	--maximal;
   429       }
   430       int idx = first[maximal];
   431       index[data[idx].item] = -2;
   432       unlace(idx);
   433       relocate_last(idx);
   434     }
   435 
   436     void erase(const Item &i) {
   437       int idx = index[i];
   438       index[data[idx].item] = -2;
   439       unlace(idx);
   440       relocate_last(idx);
   441     }
   442 
   443     Prio operator[](const Item &i) const {
   444       int idx = index[i];
   445       return data[idx].value;
   446     }
   447 
   448     void set(const Item &i, const Prio &p) {
   449       int idx = index[i];
   450       if (idx < 0) {
   451 	push(i,p);
   452       } else if (p > data[idx].value) {
   453 	decrease(i, p);
   454       } else {
   455 	increase(i, p);
   456       }
   457     }
   458 
   459     void decrease(const Item &i, const Prio &p) {
   460       int idx = index[i];
   461       unlace(idx);
   462       data[idx].value = p;
   463       if (p > maximal) {
   464 	maximal = p;
   465       }
   466       lace(idx);
   467     }
   468     
   469     void increase(const Item &i, const Prio &p) {
   470       int idx = index[i];
   471       unlace(idx);
   472       data[idx].value = p;
   473       lace(idx);
   474     }
   475 
   476     state_enum state(const Item &i) const {
   477       int idx = index[i];
   478       if (idx >= 0) idx = 0;
   479       return state_enum(idx);
   480     }
   481 
   482     void state(const Item& i, state_enum st) {
   483       switch (st) {
   484       case POST_HEAP:
   485       case PRE_HEAP:
   486         if (state(i) == IN_HEAP) {
   487           erase(i);
   488         }
   489         index[i] = st;
   490         break;
   491       case IN_HEAP:
   492         break;
   493       }
   494     }
   495 
   496   private:
   497 
   498     struct BucketItem {
   499       BucketItem(const Item& _item, int _value) 
   500 	: item(_item), value(_value) {}
   501 
   502       Item item;
   503       int value;
   504 
   505       int prev, next;
   506     };
   507 
   508     ItemIntMap& index;
   509     std::vector<int> first;
   510     std::vector<BucketItem> data;
   511     mutable int maximal;
   512 
   513   }; // class BucketHeap
   514 
   515   /// \ingroup auxdat
   516   ///
   517   /// \brief A Simplified Bucket Heap implementation.
   518   ///
   519   /// This class implements a simplified \e bucket \e heap data
   520   /// structure.  It does not provide some functionality but it faster
   521   /// and simplier data structure than the BucketHeap. The main
   522   /// difference is that the BucketHeap stores for every key a double
   523   /// linked list while this class stores just simple lists. In the
   524   /// other way it does not supports erasing each elements just the
   525   /// minimal and it does not supports key increasing, decreasing.
   526   ///
   527   /// \param _Item Type of the items to be stored.  
   528   /// \param _ItemIntMap A read and writable Item int map, used internally
   529   /// to handle the cross references.
   530   /// \param minimize If the given parameter is true then the heap gives back
   531   /// the lowest priority.
   532   ///
   533   /// \sa BucketHeap 
   534   template <typename _Item, typename _ItemIntMap, bool minimize = true >
   535   class SimpleBucketHeap {
   536 
   537   public:
   538     typedef _Item Item;
   539     typedef int Prio;
   540     typedef std::pair<Item, Prio> Pair;
   541     typedef _ItemIntMap ItemIntMap;
   542 
   543     /// \brief Type to represent the items states.
   544     ///
   545     /// Each Item element have a state associated to it. It may be "in heap",
   546     /// "pre heap" or "post heap". The latter two are indifferent from the
   547     /// heap's point of view, but may be useful to the user.
   548     ///
   549     /// The ItemIntMap \e should be initialized in such way that it maps
   550     /// PRE_HEAP (-1) to any element to be put in the heap...
   551     enum state_enum {
   552       IN_HEAP = 0,
   553       PRE_HEAP = -1,
   554       POST_HEAP = -2
   555     };
   556 
   557   public:
   558 
   559     /// \brief The constructor.
   560     ///
   561     /// The constructor.
   562     /// \param _index should be given to the constructor, since it is used
   563     /// internally to handle the cross references. The value of the map
   564     /// should be PRE_HEAP (-1) for each element.
   565     explicit SimpleBucketHeap(ItemIntMap &_index) 
   566       : index(_index), free(-1), num(0), minimal(0) {}
   567     
   568     /// \brief Returns the number of items stored in the heap.
   569     ///
   570     /// The number of items stored in the heap.
   571     int size() const { return num; }
   572     
   573     /// \brief Checks if the heap stores no items.
   574     ///
   575     /// Returns \c true if and only if the heap stores no items.
   576     bool empty() const { return num == 0; }
   577 
   578     /// \brief Make empty this heap.
   579     /// 
   580     /// Make empty this heap. It does not change the cross reference
   581     /// map.  If you want to reuse a heap what is not surely empty you
   582     /// should first clear the heap and after that you should set the
   583     /// cross reference map for each item to \c PRE_HEAP.
   584     void clear() { 
   585       data.clear(); first.clear(); free = -1; num = 0; minimal = 0;
   586     }
   587 
   588     /// \brief Insert a pair of item and priority into the heap.
   589     ///
   590     /// Adds \c p.first to the heap with priority \c p.second.
   591     /// \param p The pair to insert.
   592     void push(const Pair& p) {
   593       push(p.first, p.second);
   594     }
   595 
   596     /// \brief Insert an item into the heap with the given priority.
   597     ///    
   598     /// Adds \c i to the heap with priority \c p. 
   599     /// \param i The item to insert.
   600     /// \param p The priority of the item.
   601     void push(const Item &i, const Prio &p) {
   602       int idx;
   603       if (free == -1) {
   604         idx = data.size();
   605         data.push_back(BucketItem(i));
   606       } else {
   607         idx = free;
   608         free = data[idx].next;
   609         data[idx].item = i;
   610       }
   611       index[i] = idx;
   612       if (p >= (int)first.size()) first.resize(p + 1, -1);
   613       data[idx].next = first[p];
   614       first[p] = idx;
   615       if (p < minimal) {
   616 	minimal = p;
   617       }
   618       ++num;
   619     }
   620 
   621     /// \brief Returns the item with minimum priority.
   622     ///
   623     /// This method returns the item with minimum priority.
   624     /// \pre The heap must be nonempty.  
   625     Item top() const {
   626       while (first[minimal] == -1) {
   627 	++minimal;
   628       }
   629       return data[first[minimal]].item;
   630     }
   631 
   632     /// \brief Returns the minimum priority.
   633     ///
   634     /// It returns the minimum priority.
   635     /// \pre The heap must be nonempty.
   636     Prio prio() const {
   637       while (first[minimal] == -1) {
   638 	++minimal;
   639       }
   640       return minimal;
   641     }
   642 
   643     /// \brief Deletes the item with minimum priority.
   644     ///
   645     /// This method deletes the item with minimum priority from the heap.  
   646     /// \pre The heap must be non-empty.  
   647     void pop() {
   648       while (first[minimal] == -1) {
   649 	++minimal;
   650       }
   651       int idx = first[minimal];
   652       index[data[idx].item] = -2;
   653       first[minimal] = data[idx].next;
   654       data[idx].next = free;
   655       free = idx;
   656       --num;
   657     }
   658     
   659     /// \brief Returns the priority of \c i.
   660     ///
   661     /// This function returns the priority of item \c i.
   662     /// \warning This operator is not a constant time function
   663     /// because it scans the whole data structure to find the proper
   664     /// value.  
   665     /// \pre \c i must be in the heap.
   666     /// \param i The item.
   667     Prio operator[](const Item &i) const {
   668       for (int k = 0; k < first.size(); ++k) {
   669         int idx = first[k];
   670         while (idx != -1) {
   671           if (data[idx].item == i) {
   672             return k;
   673           }
   674           idx = data[idx].next;
   675         }
   676       }
   677       return -1;
   678     }
   679 
   680     /// \brief Returns if \c item is in, has already been in, or has 
   681     /// never been in the heap.
   682     ///
   683     /// This method returns PRE_HEAP if \c item has never been in the
   684     /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
   685     /// otherwise. In the latter case it is possible that \c item will
   686     /// get back to the heap again.
   687     /// \param i The item.
   688     state_enum state(const Item &i) const {
   689       int idx = index[i];
   690       if (idx >= 0) idx = 0;
   691       return state_enum(idx);
   692     }
   693 
   694   private:
   695 
   696     struct BucketItem {
   697       BucketItem(const Item& _item) 
   698 	: item(_item) {}
   699 
   700       Item item;
   701       int next;
   702     };
   703 
   704     ItemIntMap& index;
   705     std::vector<int> first;
   706     std::vector<BucketItem> data;
   707     int free, num;
   708     mutable int minimal;
   709 
   710   }; // class SimpleBucketHeap
   711 
   712   template <typename _Item, typename _ItemIntMap>
   713   class SimpleBucketHeap<_Item, _ItemIntMap, false> {
   714 
   715   public:
   716     typedef _Item Item;
   717     typedef int Prio;
   718     typedef std::pair<Item, Prio> Pair;
   719     typedef _ItemIntMap ItemIntMap;
   720 
   721     enum state_enum {
   722       IN_HEAP = 0,
   723       PRE_HEAP = -1,
   724       POST_HEAP = -2
   725     };
   726 
   727   public:
   728 
   729     explicit SimpleBucketHeap(ItemIntMap &_index) 
   730       : index(_index), free(-1), num(0), maximal(0) {}
   731     
   732     int size() const { return num; }
   733     
   734     bool empty() const { return num == 0; }
   735 
   736     void clear() { 
   737       data.clear(); first.clear(); free = -1; num = 0; maximal = 0;
   738     }
   739 
   740     void push(const Pair& p) {
   741       push(p.first, p.second);
   742     }
   743 
   744     void push(const Item &i, const Prio &p) {
   745       int idx;
   746       if (free == -1) {
   747         idx = data.size();
   748         data.push_back(BucketItem(i));
   749       } else {
   750         idx = free;
   751         free = data[idx].next;
   752         data[idx].item = i;
   753       }
   754       index[i] = idx;
   755       if (p >= (int)first.size()) first.resize(p + 1, -1);
   756       data[idx].next = first[p];
   757       first[p] = idx;
   758       if (p > maximal) {
   759 	maximal = p;
   760       }
   761       ++num;
   762     }
   763 
   764     Item top() const {
   765       while (first[maximal] == -1) {
   766 	--maximal;
   767       }
   768       return data[first[maximal]].item;
   769     }
   770 
   771     Prio prio() const {
   772       while (first[maximal] == -1) {
   773 	--maximal;
   774       }
   775       return maximal;
   776     }
   777 
   778     void pop() {
   779       while (first[maximal] == -1) {
   780 	--maximal;
   781       }
   782       int idx = first[maximal];
   783       index[data[idx].item] = -2;
   784       first[maximal] = data[idx].next;
   785       data[idx].next = free;
   786       free = idx;
   787       --num;
   788     }
   789     
   790     Prio operator[](const Item &i) const {
   791       for (int k = 0; k < first.size(); ++k) {
   792         int idx = first[k];
   793         while (idx != -1) {
   794           if (data[idx].item == i) {
   795             return k;
   796           }
   797           idx = data[idx].next;
   798         }
   799       }
   800       return -1;
   801     }
   802 
   803     state_enum state(const Item &i) const {
   804       int idx = index[i];
   805       if (idx >= 0) idx = 0;
   806       return state_enum(idx);
   807     }
   808 
   809   private:
   810 
   811     struct BucketItem {
   812       BucketItem(const Item& _item) : item(_item) {}
   813 
   814       Item item;
   815 
   816       int next;
   817     };
   818 
   819     ItemIntMap& index;
   820     std::vector<int> first;
   821     std::vector<BucketItem> data;
   822     int free, num;
   823     mutable int maximal;
   824 
   825   };
   826 
   827 }
   828   
   829 #endif