COIN-OR::LEMON - Graph Library

source: lemon-1.2/lemon/binom_heap.h @ 706:9314d9339475

Last change on this file since 706:9314d9339475 was 703:bb3392fe91f2, checked in by Peter Kovacs <kpeter@…>, 15 years ago

Improve and unify the doc + names in the new heaps (#301)

File size: 14.6 KB
RevLine 
[703]1/* -*- mode: C++; indent-tabs-mode: nil; -*-
[701]2 *
[703]3 * This file is a part of LEMON, a generic C++ optimization library.
[701]4 *
[703]5 * Copyright (C) 2003-2009
[701]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_BINOM_HEAP_H
20#define LEMON_BINOM_HEAP_H
21
22///\file
[703]23///\ingroup heaps
[701]24///\brief Binomial Heap implementation.
25
26#include <vector>
[703]27#include <utility>
[701]28#include <functional>
29#include <lemon/math.h>
30#include <lemon/counter.h>
31
32namespace lemon {
33
[703]34  /// \ingroup heaps
[701]35  ///
[703]36  ///\brief Binomial heap data structure.
[701]37  ///
[703]38  /// This class implements the \e binomial \e heap data structure.
39  /// It fully conforms to the \ref concepts::Heap "heap concept".
[701]40  ///
[703]41  /// The methods \ref increase() and \ref erase() are not efficient
42  /// in a binomial heap. In case of many calls of these operations,
43  /// it is better to use other heap structure, e.g. \ref BinHeap
44  /// "binary heap".
[701]45  ///
[703]46  /// \tparam PR Type of the priorities of the items.
47  /// \tparam IM A read-writable item map with \c int values, used
48  /// internally to handle the cross references.
49  /// \tparam CMP A functor class for comparing the priorities.
50  /// The default is \c std::less<PR>.
[701]51#ifdef DOXYGEN
[703]52  template <typename PR, typename IM, typename CMP>
[701]53#else
[703]54  template <typename PR, typename IM, typename CMP = std::less<PR> >
[701]55#endif
56  class BinomHeap {
57  public:
[703]58    /// Type of the item-int map.
59    typedef IM ItemIntMap;
60    /// Type of the priorities.
61    typedef PR Prio;
62    /// Type of the items stored in the heap.
[701]63    typedef typename ItemIntMap::Key Item;
[703]64    /// Functor type for comparing the priorities.
65    typedef CMP Compare;
66
67    /// \brief Type to represent the states of the items.
68    ///
69    /// Each item has a state associated to it. It can be "in heap",
70    /// "pre-heap" or "post-heap". The latter two are indifferent from the
71    /// heap's point of view, but may be useful to the user.
72    ///
73    /// The item-int map must be initialized in such way that it assigns
74    /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
75    enum State {
76      IN_HEAP = 0,    ///< = 0.
77      PRE_HEAP = -1,  ///< = -1.
78      POST_HEAP = -2  ///< = -2.
79    };
[701]80
81  private:
82    class store;
83
[703]84    std::vector<store> _data;
85    int _min, _head;
86    ItemIntMap &_iim;
87    Compare _comp;
88    int _num_items;
[701]89
90  public:
[703]91    /// \brief Constructor.
92    ///
93    /// Constructor.
94    /// \param map A map that assigns \c int values to the items.
95    /// It is used internally to handle the cross references.
96    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
97    explicit BinomHeap(ItemIntMap &map)
98      : _min(0), _head(-1), _iim(map), _num_items(0) {}
[701]99
[703]100    /// \brief Constructor.
[701]101    ///
[703]102    /// Constructor.
103    /// \param map A map that assigns \c int values to the items.
104    /// It is used internally to handle the cross references.
105    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
106    /// \param comp The function object used for comparing the priorities.
107    BinomHeap(ItemIntMap &map, const Compare &comp)
108      : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {}
[701]109
110    /// \brief The number of items stored in the heap.
111    ///
[703]112    /// This function returns the number of items stored in the heap.
113    int size() const { return _num_items; }
[701]114
[703]115    /// \brief Check if the heap is empty.
[701]116    ///
[703]117    /// This function returns \c true if the heap is empty.
118    bool empty() const { return _num_items==0; }
[701]119
[703]120    /// \brief Make the heap empty.
[701]121    ///
[703]122    /// This functon makes the heap empty.
123    /// It does not change the cross reference map. If you want to reuse
124    /// a heap that is not surely empty, you should first clear it and
125    /// then you should set the cross reference map to \c PRE_HEAP
126    /// for each item.
[701]127    void clear() {
[703]128      _data.clear(); _min=0; _num_items=0; _head=-1;
[701]129    }
130
[703]131    /// \brief Set the priority of an item or insert it, if it is
132    /// not stored in the heap.
[701]133    ///
[703]134    /// This method sets the priority of the given item if it is
135    /// already stored in the heap. Otherwise it inserts the given
136    /// item into the heap with the given priority.
137    /// \param item The item.
138    /// \param value The priority.
[701]139    void set (const Item& item, const Prio& value) {
[703]140      int i=_iim[item];
141      if ( i >= 0 && _data[i].in ) {
142        if ( _comp(value, _data[i].prio) ) decrease(item, value);
143        if ( _comp(_data[i].prio, value) ) increase(item, value);
[701]144      } else push(item, value);
145    }
146
[703]147    /// \brief Insert an item into the heap with the given priority.
[701]148    ///
[703]149    /// This function inserts the given item into the heap with the
150    /// given priority.
151    /// \param item The item to insert.
152    /// \param value The priority of the item.
153    /// \pre \e item must not be stored in the heap.
[701]154    void push (const Item& item, const Prio& value) {
[703]155      int i=_iim[item];
[701]156      if ( i<0 ) {
[703]157        int s=_data.size();
158        _iim.set( item,s );
[701]159        store st;
160        st.name=item;
[703]161        _data.push_back(st);
[701]162        i=s;
163      }
164      else {
[703]165        _data[i].parent=_data[i].right_neighbor=_data[i].child=-1;
166        _data[i].degree=0;
167        _data[i].in=true;
[701]168      }
[703]169      _data[i].prio=value;
[701]170
[703]171      if( 0==_num_items ) { _head=i; _min=i; }
[701]172      else { merge(i); }
173
[703]174      _min = findMin();
[701]175
[703]176      ++_num_items;
[701]177    }
178
[703]179    /// \brief Return the item having minimum priority.
[701]180    ///
[703]181    /// This function returns the item having minimum priority.
182    /// \pre The heap must be non-empty.
183    Item top() const { return _data[_min].name; }
[701]184
[703]185    /// \brief The minimum priority.
[701]186    ///
[703]187    /// This function returns the minimum priority.
188    /// \pre The heap must be non-empty.
189    Prio prio() const { return _data[_min].prio; }
[701]190
[703]191    /// \brief The priority of the given item.
[701]192    ///
[703]193    /// This function returns the priority of the given item.
194    /// \param item The item.
195    /// \pre \e item must be in the heap.
[701]196    const Prio& operator[](const Item& item) const {
[703]197      return _data[_iim[item]].prio;
[701]198    }
199
[703]200    /// \brief Remove the item having minimum priority.
[701]201    ///
[703]202    /// This function removes the item having minimum priority.
[701]203    /// \pre The heap must be non-empty.
204    void pop() {
[703]205      _data[_min].in=false;
[701]206
207      int head_child=-1;
[703]208      if ( _data[_min].child!=-1 ) {
209        int child=_data[_min].child;
[701]210        int neighb;
211        int prev=-1;
212        while( child!=-1 ) {
[703]213          neighb=_data[child].right_neighbor;
214          _data[child].parent=-1;
215          _data[child].right_neighbor=prev;
[701]216          head_child=child;
217          prev=child;
218          child=neighb;
219        }
220      }
221
222      // The first case is that there are only one root.
[703]223      if ( -1==_data[_head].right_neighbor ) {
224        _head=head_child;
[701]225      }
226      // The case where there are more roots.
227      else {
[703]228        if( _head!=_min )  { unlace(_min); }
229        else { _head=_data[_head].right_neighbor; }
[701]230
231        merge(head_child);
232      }
[703]233      _min=findMin();
234      --_num_items;
[701]235    }
236
[703]237    /// \brief Remove the given item from the heap.
[701]238    ///
[703]239    /// This function removes the given item from the heap if it is
240    /// already stored.
241    /// \param item The item to delete.
242    /// \pre \e item must be in the heap.
[701]243    void erase (const Item& item) {
[703]244      int i=_iim[item];
245      if ( i >= 0 && _data[i].in ) {
246        decrease( item, _data[_min].prio-1 );
[701]247        pop();
248      }
249    }
250
[703]251    /// \brief Decrease the priority of an item to the given value.
[701]252    ///
[703]253    /// This function decreases the priority of an item to the given value.
254    /// \param item The item.
255    /// \param value The priority.
256    /// \pre \e item must be stored in the heap with priority at least \e value.
[701]257    void decrease (Item item, const Prio& value) {
[703]258      int i=_iim[item];
[701]259
[703]260      if( _comp( value,_data[i].prio ) ) {
261        _data[i].prio=value;
[701]262
[703]263        int p_loc=_data[i].parent, loc=i;
[701]264        int parent, child, neighb;
265
[703]266        while( -1!=p_loc && _comp(_data[loc].prio,_data[p_loc].prio) ) {
[701]267
268          // parent set for other loc_child
[703]269          child=_data[loc].child;
[701]270          while( -1!=child ) {
[703]271            _data[child].parent=p_loc;
272            child=_data[child].right_neighbor;
[701]273          }
274
275          // parent set for other p_loc_child
[703]276          child=_data[p_loc].child;
[701]277          while( -1!=child ) {
[703]278            _data[child].parent=loc;
279            child=_data[child].right_neighbor;
[701]280          }
281
[703]282          child=_data[p_loc].child;
283          _data[p_loc].child=_data[loc].child;
[701]284          if( child==loc )
285            child=p_loc;
[703]286          _data[loc].child=child;
[701]287
288          // left_neighb set for p_loc
[703]289          if( _data[loc].child!=p_loc ) {
290            while( _data[child].right_neighbor!=loc )
291              child=_data[child].right_neighbor;
292            _data[child].right_neighbor=p_loc;
[701]293          }
294
295          // left_neighb set for loc
[703]296          parent=_data[p_loc].parent;
297          if( -1!=parent ) child=_data[parent].child;
298          else child=_head;
[701]299
300          if( child!=p_loc ) {
[703]301            while( _data[child].right_neighbor!=p_loc )
302              child=_data[child].right_neighbor;
303            _data[child].right_neighbor=loc;
[701]304          }
305
[703]306          neighb=_data[p_loc].right_neighbor;
307          _data[p_loc].right_neighbor=_data[loc].right_neighbor;
308          _data[loc].right_neighbor=neighb;
[701]309
[703]310          _data[p_loc].parent=loc;
311          _data[loc].parent=parent;
[701]312
[703]313          if( -1!=parent && _data[parent].child==p_loc )
314            _data[parent].child=loc;
[701]315
316          /*if new parent will be the first root*/
[703]317          if( _head==p_loc )
318            _head=loc;
[701]319
[703]320          p_loc=_data[loc].parent;
[701]321        }
322      }
[703]323      if( _comp(value,_data[_min].prio) ) {
324        _min=i;
[701]325      }
326    }
327
[703]328    /// \brief Increase the priority of an item to the given value.
[701]329    ///
[703]330    /// This function increases the priority of an item to the given value.
331    /// \param item The item.
332    /// \param value The priority.
333    /// \pre \e item must be stored in the heap with priority at most \e value.
[701]334    void increase (Item item, const Prio& value) {
335      erase(item);
336      push(item, value);
337    }
338
[703]339    /// \brief Return the state of an item.
[701]340    ///
[703]341    /// This method returns \c PRE_HEAP if the given item has never
342    /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
343    /// and \c POST_HEAP otherwise.
344    /// In the latter case it is possible that the item will get back
345    /// to the heap again.
346    /// \param item The item.
[701]347    State state(const Item &item) const {
[703]348      int i=_iim[item];
[701]349      if( i>=0 ) {
[703]350        if ( _data[i].in ) i=0;
[701]351        else i=-2;
352      }
353      return State(i);
354    }
355
[703]356    /// \brief Set the state of an item in the heap.
[701]357    ///
[703]358    /// This function sets the state of the given item in the heap.
359    /// It can be used to manually clear the heap when it is important
360    /// to achive better time complexity.
[701]361    /// \param i The item.
362    /// \param st The state. It should not be \c IN_HEAP.
363    void state(const Item& i, State st) {
364      switch (st) {
365      case POST_HEAP:
366      case PRE_HEAP:
367        if (state(i) == IN_HEAP) {
368          erase(i);
369        }
[703]370        _iim[i] = st;
[701]371        break;
372      case IN_HEAP:
373        break;
374      }
375    }
376
377  private:
[703]378    int findMin() {
[701]379      int min_loc=-1, min_val;
[703]380      int x=_head;
[701]381      if( x!=-1 ) {
[703]382        min_val=_data[x].prio;
[701]383        min_loc=x;
[703]384        x=_data[x].right_neighbor;
[701]385
386        while( x!=-1 ) {
[703]387          if( _comp( _data[x].prio,min_val ) ) {
388            min_val=_data[x].prio;
[701]389            min_loc=x;
390          }
[703]391          x=_data[x].right_neighbor;
[701]392        }
393      }
394      return min_loc;
395    }
396
397    void merge(int a) {
398      interleave(a);
399
[703]400      int x=_head;
[701]401      if( -1!=x ) {
[703]402        int x_prev=-1, x_next=_data[x].right_neighbor;
[701]403        while( -1!=x_next ) {
[703]404          if( _data[x].degree!=_data[x_next].degree || ( -1!=_data[x_next].right_neighbor && _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
[701]405            x_prev=x;
406            x=x_next;
407          }
408          else {
[703]409            if( _comp(_data[x].prio,_data[x_next].prio) ) {
410              _data[x].right_neighbor=_data[x_next].right_neighbor;
[701]411              fuse(x_next,x);
412            }
413            else {
[703]414              if( -1==x_prev ) { _head=x_next; }
[701]415              else {
[703]416                _data[x_prev].right_neighbor=x_next;
[701]417              }
418              fuse(x,x_next);
419              x=x_next;
420            }
421          }
[703]422          x_next=_data[x].right_neighbor;
[701]423        }
424      }
425    }
426
427    void interleave(int a) {
428      int other=-1, head_other=-1;
429
[703]430      while( -1!=a || -1!=_head ) {
[701]431        if( -1==a ) {
432          if( -1==head_other ) {
[703]433            head_other=_head;
[701]434          }
435          else {
[703]436            _data[other].right_neighbor=_head;
[701]437          }
[703]438          _head=-1;
[701]439        }
[703]440        else if( -1==_head ) {
[701]441          if( -1==head_other ) {
442            head_other=a;
443          }
444          else {
[703]445            _data[other].right_neighbor=a;
[701]446          }
447          a=-1;
448        }
449        else {
[703]450          if( _data[a].degree<_data[_head].degree ) {
[701]451            if( -1==head_other ) {
452              head_other=a;
453            }
454            else {
[703]455              _data[other].right_neighbor=a;
[701]456            }
457            other=a;
[703]458            a=_data[a].right_neighbor;
[701]459          }
460          else {
461            if( -1==head_other ) {
[703]462              head_other=_head;
[701]463            }
464            else {
[703]465              _data[other].right_neighbor=_head;
[701]466            }
[703]467            other=_head;
468            _head=_data[_head].right_neighbor;
[701]469          }
470        }
471      }
[703]472      _head=head_other;
[701]473    }
474
475    // Lacing a under b
476    void fuse(int a, int b) {
[703]477      _data[a].parent=b;
478      _data[a].right_neighbor=_data[b].child;
479      _data[b].child=a;
[701]480
[703]481      ++_data[b].degree;
[701]482    }
483
484    // It is invoked only if a has siblings.
485    void unlace(int a) {
[703]486      int neighb=_data[a].right_neighbor;
487      int other=_head;
[701]488
[703]489      while( _data[other].right_neighbor!=a )
490        other=_data[other].right_neighbor;
491      _data[other].right_neighbor=neighb;
[701]492    }
493
494  private:
495
496    class store {
497      friend class BinomHeap;
498
499      Item name;
500      int parent;
501      int right_neighbor;
502      int child;
503      int degree;
504      bool in;
505      Prio prio;
506
507      store() : parent(-1), right_neighbor(-1), child(-1), degree(0), in(true) {}
508    };
509  };
510
511} //namespace lemon
512
513#endif //LEMON_BINOM_HEAP_H
514
Note: See TracBrowser for help on using the repository browser.