COIN-OR::LEMON - Graph Library

source: lemon/lemon/binomial_heap.h @ 956:141f9c0db4a3

Last change on this file since 956:141f9c0db4a3 was 956:141f9c0db4a3, checked in by Alpar Juttner <alpar@…>, 14 years ago

Unify the sources (#339)

File size: 12.9 KB
RevLine 
[750]1/* -*- mode: C++; indent-tabs-mode: nil; -*-
[748]2 *
[750]3 * This file is a part of LEMON, a generic C++ optimization library.
[748]4 *
[956]5 * Copyright (C) 2003-2010
[748]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
[929]19#ifndef LEMON_BINOMIAL_HEAP_H
20#define LEMON_BINOMIAL_HEAP_H
[748]21
22///\file
[750]23///\ingroup heaps
[748]24///\brief Binomial Heap implementation.
25
26#include <vector>
[750]27#include <utility>
[748]28#include <functional>
29#include <lemon/math.h>
30#include <lemon/counter.h>
31
32namespace lemon {
33
[750]34  /// \ingroup heaps
[748]35  ///
[750]36  ///\brief Binomial heap data structure.
[748]37  ///
[750]38  /// This class implements the \e binomial \e heap data structure.
39  /// It fully conforms to the \ref concepts::Heap "heap concept".
[748]40  ///
[750]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".
[748]45  ///
[750]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>.
[748]51#ifdef DOXYGEN
[750]52  template <typename PR, typename IM, typename CMP>
[748]53#else
[750]54  template <typename PR, typename IM, typename CMP = std::less<PR> >
[748]55#endif
[929]56  class BinomialHeap {
[748]57  public:
[750]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.
[748]63    typedef typename ItemIntMap::Key Item;
[750]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    };
[748]80
81  private:
[754]82    class Store;
[748]83
[754]84    std::vector<Store> _data;
[750]85    int _min, _head;
86    ItemIntMap &_iim;
87    Compare _comp;
88    int _num_items;
[748]89
90  public:
[750]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.
[929]97    explicit BinomialHeap(ItemIntMap &map)
[750]98      : _min(0), _head(-1), _iim(map), _num_items(0) {}
[748]99
[750]100    /// \brief Constructor.
[748]101    ///
[750]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.
[929]107    BinomialHeap(ItemIntMap &map, const Compare &comp)
[750]108      : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {}
[748]109
110    /// \brief The number of items stored in the heap.
111    ///
[750]112    /// This function returns the number of items stored in the heap.
113    int size() const { return _num_items; }
[748]114
[750]115    /// \brief Check if the heap is empty.
[748]116    ///
[750]117    /// This function returns \c true if the heap is empty.
118    bool empty() const { return _num_items==0; }
[748]119
[750]120    /// \brief Make the heap empty.
[748]121    ///
[750]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.
[748]127    void clear() {
[750]128      _data.clear(); _min=0; _num_items=0; _head=-1;
[748]129    }
130
[750]131    /// \brief Set the priority of an item or insert it, if it is
132    /// not stored in the heap.
[748]133    ///
[750]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.
[748]139    void set (const Item& item, const Prio& value) {
[750]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);
[748]144      } else push(item, value);
145    }
146
[750]147    /// \brief Insert an item into the heap with the given priority.
[748]148    ///
[750]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.
[748]154    void push (const Item& item, const Prio& value) {
[750]155      int i=_iim[item];
[748]156      if ( i<0 ) {
[750]157        int s=_data.size();
158        _iim.set( item,s );
[754]159        Store st;
[748]160        st.name=item;
[754]161        st.prio=value;
[750]162        _data.push_back(st);
[748]163        i=s;
164      }
165      else {
[750]166        _data[i].parent=_data[i].right_neighbor=_data[i].child=-1;
167        _data[i].degree=0;
168        _data[i].in=true;
[754]169        _data[i].prio=value;
[748]170      }
171
[754]172      if( 0==_num_items ) {
173        _head=i;
174        _min=i;
175      } else {
176        merge(i);
177        if( _comp(_data[i].prio, _data[_min].prio) ) _min=i;
178      }
[750]179      ++_num_items;
[748]180    }
181
[750]182    /// \brief Return the item having minimum priority.
[748]183    ///
[750]184    /// This function returns the item having minimum priority.
185    /// \pre The heap must be non-empty.
186    Item top() const { return _data[_min].name; }
[748]187
[750]188    /// \brief The minimum priority.
[748]189    ///
[750]190    /// This function returns the minimum priority.
191    /// \pre The heap must be non-empty.
192    Prio prio() const { return _data[_min].prio; }
[748]193
[750]194    /// \brief The priority of the given item.
[748]195    ///
[750]196    /// This function returns the priority of the given item.
197    /// \param item The item.
198    /// \pre \e item must be in the heap.
[748]199    const Prio& operator[](const Item& item) const {
[750]200      return _data[_iim[item]].prio;
[748]201    }
202
[750]203    /// \brief Remove the item having minimum priority.
[748]204    ///
[750]205    /// This function removes the item having minimum priority.
[748]206    /// \pre The heap must be non-empty.
207    void pop() {
[750]208      _data[_min].in=false;
[748]209
210      int head_child=-1;
[750]211      if ( _data[_min].child!=-1 ) {
212        int child=_data[_min].child;
[748]213        int neighb;
214        while( child!=-1 ) {
[750]215          neighb=_data[child].right_neighbor;
216          _data[child].parent=-1;
[754]217          _data[child].right_neighbor=head_child;
[748]218          head_child=child;
219          child=neighb;
220        }
221      }
222
[754]223      if ( _data[_head].right_neighbor==-1 ) {
224        // there was only one root
[750]225        _head=head_child;
[748]226      }
227      else {
[754]228        // there were more roots
[750]229        if( _head!=_min )  { unlace(_min); }
230        else { _head=_data[_head].right_neighbor; }
[748]231        merge(head_child);
232      }
[750]233      _min=findMin();
234      --_num_items;
[748]235    }
236
[750]237    /// \brief Remove the given item from the heap.
[748]238    ///
[750]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.
[748]243    void erase (const Item& item) {
[750]244      int i=_iim[item];
245      if ( i >= 0 && _data[i].in ) {
246        decrease( item, _data[_min].prio-1 );
[748]247        pop();
248      }
249    }
250
[750]251    /// \brief Decrease the priority of an item to the given value.
[748]252    ///
[750]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.
[748]257    void decrease (Item item, const Prio& value) {
[750]258      int i=_iim[item];
[754]259      int p=_data[i].parent;
260      _data[i].prio=value;
[956]261
[754]262      while( p!=-1 && _comp(value, _data[p].prio) ) {
263        _data[i].name=_data[p].name;
264        _data[i].prio=_data[p].prio;
265        _data[p].name=item;
266        _data[p].prio=value;
267        _iim[_data[i].name]=i;
268        i=p;
269        p=_data[p].parent;
[748]270      }
[754]271      _iim[item]=i;
272      if ( _comp(value, _data[_min].prio) ) _min=i;
[748]273    }
274
[750]275    /// \brief Increase the priority of an item to the given value.
[748]276    ///
[750]277    /// This function increases the priority of an item to the given value.
278    /// \param item The item.
279    /// \param value The priority.
280    /// \pre \e item must be stored in the heap with priority at most \e value.
[748]281    void increase (Item item, const Prio& value) {
282      erase(item);
283      push(item, value);
284    }
285
[750]286    /// \brief Return the state of an item.
[748]287    ///
[750]288    /// This method returns \c PRE_HEAP if the given item has never
289    /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
290    /// and \c POST_HEAP otherwise.
291    /// In the latter case it is possible that the item will get back
292    /// to the heap again.
293    /// \param item The item.
[748]294    State state(const Item &item) const {
[750]295      int i=_iim[item];
[748]296      if( i>=0 ) {
[750]297        if ( _data[i].in ) i=0;
[748]298        else i=-2;
299      }
300      return State(i);
301    }
302
[750]303    /// \brief Set the state of an item in the heap.
[748]304    ///
[750]305    /// This function sets the state of the given item in the heap.
306    /// It can be used to manually clear the heap when it is important
307    /// to achive better time complexity.
[748]308    /// \param i The item.
309    /// \param st The state. It should not be \c IN_HEAP.
310    void state(const Item& i, State st) {
311      switch (st) {
312      case POST_HEAP:
313      case PRE_HEAP:
314        if (state(i) == IN_HEAP) {
315          erase(i);
316        }
[750]317        _iim[i] = st;
[748]318        break;
319      case IN_HEAP:
320        break;
321      }
322    }
323
324  private:
[956]325
[754]326    // Find the minimum of the roots
[750]327    int findMin() {
[754]328      if( _head!=-1 ) {
329        int min_loc=_head, min_val=_data[_head].prio;
330        for( int x=_data[_head].right_neighbor; x!=-1;
331             x=_data[x].right_neighbor ) {
[750]332          if( _comp( _data[x].prio,min_val ) ) {
333            min_val=_data[x].prio;
[748]334            min_loc=x;
335          }
336        }
[754]337        return min_loc;
[748]338      }
[754]339      else return -1;
[748]340    }
341
[754]342    // Merge the heap with another heap starting at the given position
[748]343    void merge(int a) {
[754]344      if( _head==-1 || a==-1 ) return;
345      if( _data[a].right_neighbor==-1 &&
346          _data[a].degree<=_data[_head].degree ) {
347        _data[a].right_neighbor=_head;
348        _head=a;
349      } else {
350        interleave(a);
351      }
352      if( _data[_head].right_neighbor==-1 ) return;
[956]353
[750]354      int x=_head;
[754]355      int x_prev=-1, x_next=_data[x].right_neighbor;
356      while( x_next!=-1 ) {
357        if( _data[x].degree!=_data[x_next].degree ||
358            ( _data[x_next].right_neighbor!=-1 &&
359              _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
360          x_prev=x;
361          x=x_next;
362        }
363        else {
364          if( _comp(_data[x_next].prio,_data[x].prio) ) {
365            if( x_prev==-1 ) {
366              _head=x_next;
367            } else {
368              _data[x_prev].right_neighbor=x_next;
369            }
370            fuse(x,x_next);
[748]371            x=x_next;
372          }
373          else {
[754]374            _data[x].right_neighbor=_data[x_next].right_neighbor;
375            fuse(x_next,x);
[748]376          }
377        }
[754]378        x_next=_data[x].right_neighbor;
[748]379      }
380    }
381
[754]382    // Interleave the elements of the given list into the list of the roots
[748]383    void interleave(int a) {
[754]384      int p=_head, q=a;
385      int curr=_data.size();
386      _data.push_back(Store());
[956]387
[754]388      while( p!=-1 || q!=-1 ) {
389        if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) {
390          _data[curr].right_neighbor=p;
391          curr=p;
392          p=_data[p].right_neighbor;
[748]393        }
394        else {
[754]395          _data[curr].right_neighbor=q;
396          curr=q;
397          q=_data[q].right_neighbor;
[748]398        }
399      }
[956]400
[754]401      _head=_data.back().right_neighbor;
402      _data.pop_back();
[748]403    }
404
[754]405    // Lace node a under node b
[748]406    void fuse(int a, int b) {
[750]407      _data[a].parent=b;
408      _data[a].right_neighbor=_data[b].child;
409      _data[b].child=a;
[748]410
[750]411      ++_data[b].degree;
[748]412    }
413
[754]414    // Unlace node a (if it has siblings)
[748]415    void unlace(int a) {
[750]416      int neighb=_data[a].right_neighbor;
417      int other=_head;
[748]418
[750]419      while( _data[other].right_neighbor!=a )
420        other=_data[other].right_neighbor;
421      _data[other].right_neighbor=neighb;
[748]422    }
423
424  private:
425
[754]426    class Store {
[929]427      friend class BinomialHeap;
[748]428
429      Item name;
430      int parent;
431      int right_neighbor;
432      int child;
433      int degree;
434      bool in;
435      Prio prio;
436
[754]437      Store() : parent(-1), right_neighbor(-1), child(-1), degree(0),
438        in(true) {}
[748]439    };
440  };
441
442} //namespace lemon
443
[929]444#endif //LEMON_BINOMIAL_HEAP_H
[748]445
Note: See TracBrowser for help on using the repository browser.