lemon/pairing_heap.h
changeset 748 d1a9224f1e30
child 749 bdc7dfc8c054
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lemon/pairing_heap.h	Thu Jul 09 02:38:01 2009 +0200
     1.3 @@ -0,0 +1,469 @@
     1.4 +/* -*- C++ -*-
     1.5 + *
     1.6 + * This file is a part of LEMON, a generic C++ optimization library
     1.7 + *
     1.8 + * Copyright (C) 2003-2008
     1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    1.11 + *
    1.12 + * Permission to use, modify and distribute this software is granted
    1.13 + * provided that this copyright notice appears in all copies. For
    1.14 + * precise terms see the accompanying LICENSE file.
    1.15 + *
    1.16 + * This software is provided "AS IS" with no warranty of any kind,
    1.17 + * express or implied, and with no claim as to its suitability for any
    1.18 + * purpose.
    1.19 + *
    1.20 + */
    1.21 +
    1.22 +#ifndef LEMON_PAIRING_HEAP_H
    1.23 +#define LEMON_PAIRING_HEAP_H
    1.24 +
    1.25 +///\file
    1.26 +///\ingroup auxdat
    1.27 +///\brief Pairing Heap implementation.
    1.28 +
    1.29 +#include <vector>
    1.30 +#include <functional>
    1.31 +#include <lemon/math.h>
    1.32 +
    1.33 +namespace lemon {
    1.34 +
    1.35 +  /// \ingroup auxdat
    1.36 +  ///
    1.37 +  ///\brief Pairing Heap.
    1.38 +  ///
    1.39 +  ///This class implements the \e Pairing \e heap data structure. A \e heap
    1.40 +  ///is a data structure for storing items with specified values called \e
    1.41 +  ///priorities in such a way that finding the item with minimum priority is
    1.42 +  ///efficient. \c Compare specifies the ordering of the priorities. In a heap
    1.43 +  ///one can change the priority of an item, add or erase an item, etc.
    1.44 +  ///
    1.45 +  ///The methods \ref increase and \ref erase are not efficient in a Pairing
    1.46 +  ///heap. In case of many calls to these operations, it is better to use a
    1.47 +  ///\ref BinHeap "binary heap".
    1.48 +  ///
    1.49 +  ///\param _Prio Type of the priority of the items.
    1.50 +  ///\param _ItemIntMap A read and writable Item int map, used internally
    1.51 +  ///to handle the cross references.
    1.52 +  ///\param _Compare A class for the ordering of the priorities. The
    1.53 +  ///default is \c std::less<_Prio>.
    1.54 +  ///
    1.55 +  ///\sa BinHeap
    1.56 +  ///\sa Dijkstra
    1.57 +  ///\author Dorian Batha
    1.58 +
    1.59 +#ifdef DOXYGEN
    1.60 +  template <typename _Prio,
    1.61 +            typename _ItemIntMap,
    1.62 +            typename _Compare>
    1.63 +#else
    1.64 +  template <typename _Prio,
    1.65 +            typename _ItemIntMap,
    1.66 +            typename _Compare = std::less<_Prio> >
    1.67 +#endif
    1.68 +  class PairingHeap {
    1.69 +  public:
    1.70 +    typedef _ItemIntMap ItemIntMap;
    1.71 +    typedef _Prio Prio;
    1.72 +    typedef typename ItemIntMap::Key Item;
    1.73 +    typedef std::pair<Item,Prio> Pair;
    1.74 +    typedef _Compare Compare;
    1.75 +
    1.76 +  private:
    1.77 +    class store;
    1.78 +
    1.79 +    std::vector<store> container;
    1.80 +    int minimum;
    1.81 +    ItemIntMap &iimap;
    1.82 +    Compare comp;
    1.83 +    int num_items;
    1.84 +
    1.85 +  public:
    1.86 +    ///Status of the nodes
    1.87 +    enum State {
    1.88 +      ///The node is in the heap
    1.89 +      IN_HEAP = 0,
    1.90 +      ///The node has never been in the heap
    1.91 +      PRE_HEAP = -1,
    1.92 +      ///The node was in the heap but it got out of it
    1.93 +      POST_HEAP = -2
    1.94 +    };
    1.95 +
    1.96 +    /// \brief The constructor
    1.97 +    ///
    1.98 +    /// \c _iimap should be given to the constructor, since it is
    1.99 +    ///   used internally to handle the cross references.
   1.100 +    explicit PairingHeap(ItemIntMap &_iimap)
   1.101 +      : minimum(0), iimap(_iimap), num_items(0) {}
   1.102 +
   1.103 +    /// \brief The constructor
   1.104 +    ///
   1.105 +    /// \c _iimap should be given to the constructor, since it is used
   1.106 +    /// internally to handle the cross references. \c _comp is an
   1.107 +    /// object for ordering of the priorities.
   1.108 +    PairingHeap(ItemIntMap &_iimap, const Compare &_comp)
   1.109 +      : minimum(0), iimap(_iimap), comp(_comp), num_items(0) {}
   1.110 +
   1.111 +    /// \brief The number of items stored in the heap.
   1.112 +    ///
   1.113 +    /// Returns the number of items stored in the heap.
   1.114 +    int size() const { return num_items; }
   1.115 +
   1.116 +    /// \brief Checks if the heap stores no items.
   1.117 +    ///
   1.118 +    ///   Returns \c true if and only if the heap stores no items.
   1.119 +    bool empty() const { return num_items==0; }
   1.120 +
   1.121 +    /// \brief Make empty this heap.
   1.122 +    ///
   1.123 +    /// Make empty this heap. It does not change the cross reference
   1.124 +    /// map.  If you want to reuse a heap what is not surely empty you
   1.125 +    /// should first clear the heap and after that you should set the
   1.126 +    /// cross reference map for each item to \c PRE_HEAP.
   1.127 +    void clear() {
   1.128 +      container.clear();
   1.129 +      minimum = 0;
   1.130 +      num_items = 0;
   1.131 +    }
   1.132 +
   1.133 +    /// \brief \c item gets to the heap with priority \c value independently
   1.134 +    /// if \c item was already there.
   1.135 +    ///
   1.136 +    /// This method calls \ref push(\c item, \c value) if \c item is not
   1.137 +    /// stored in the heap and it calls \ref decrease(\c item, \c value) or
   1.138 +    /// \ref increase(\c item, \c value) otherwise.
   1.139 +    void set (const Item& item, const Prio& value) {
   1.140 +      int i=iimap[item];
   1.141 +      if ( i>=0 && container[i].in ) {
   1.142 +        if ( comp(value, container[i].prio) ) decrease(item, value);
   1.143 +        if ( comp(container[i].prio, value) ) increase(item, value);
   1.144 +      } else push(item, value);
   1.145 +    }
   1.146 +
   1.147 +    /// \brief Adds \c item to the heap with priority \c value.
   1.148 +    ///
   1.149 +    /// Adds \c item to the heap with priority \c value.
   1.150 +    /// \pre \c item must not be stored in the heap.
   1.151 +    void push (const Item& item, const Prio& value) {
   1.152 +      int i=iimap[item];
   1.153 +      if( i<0 ) {
   1.154 +        int s=container.size();
   1.155 +        iimap.set(item, s);
   1.156 +        store st;
   1.157 +        st.name=item;
   1.158 +        container.push_back(st);
   1.159 +        i=s;
   1.160 +      } else {
   1.161 +        container[i].parent=container[i].child=-1;
   1.162 +        container[i].left_child=false;
   1.163 +        container[i].degree=0;
   1.164 +        container[i].in=true;
   1.165 +      }
   1.166 +
   1.167 +      container[i].prio=value;
   1.168 +
   1.169 +      if ( num_items!=0 ) {
   1.170 +        if ( comp( value, container[minimum].prio) ) {
   1.171 +          fuse(i,minimum);
   1.172 +          minimum=i;
   1.173 +        }
   1.174 +        else fuse(minimum,i);
   1.175 +      }
   1.176 +      else minimum=i;
   1.177 +
   1.178 +      ++num_items;
   1.179 +    }
   1.180 +
   1.181 +    /// \brief Returns the item with minimum priority relative to \c Compare.
   1.182 +    ///
   1.183 +    /// This method returns the item with minimum priority relative to \c
   1.184 +    /// Compare.
   1.185 +    /// \pre The heap must be nonempty.
   1.186 +    Item top() const { return container[minimum].name; }
   1.187 +
   1.188 +    /// \brief Returns the minimum priority relative to \c Compare.
   1.189 +    ///
   1.190 +    /// It returns the minimum priority relative to \c Compare.
   1.191 +    /// \pre The heap must be nonempty.
   1.192 +    const Prio& prio() const { return container[minimum].prio; }
   1.193 +
   1.194 +    /// \brief Returns the priority of \c item.
   1.195 +    ///
   1.196 +    /// It returns the priority of \c item.
   1.197 +    /// \pre \c item must be in the heap.
   1.198 +    const Prio& operator[](const Item& item) const {
   1.199 +      return container[iimap[item]].prio;
   1.200 +    }
   1.201 +
   1.202 +    /// \brief Deletes the item with minimum priority relative to \c Compare.
   1.203 +    ///
   1.204 +    /// This method deletes the item with minimum priority relative to \c
   1.205 +    /// Compare from the heap.
   1.206 +    /// \pre The heap must be non-empty.
   1.207 +    void pop() {
   1.208 +      int TreeArray[num_items];
   1.209 +      int i=0, num_child=0, child_right = 0;
   1.210 +      container[minimum].in=false;
   1.211 +
   1.212 +      if( -1!=container[minimum].child ) {
   1.213 +        i=container[minimum].child;
   1.214 +        TreeArray[num_child] = i;
   1.215 +        container[i].parent = -1;
   1.216 +        container[minimum].child = -1;
   1.217 +
   1.218 +        ++num_child;
   1.219 +        int ch=-1;
   1.220 +        while( container[i].child!=-1 ) {
   1.221 +          ch=container[i].child;
   1.222 +          if( container[ch].left_child && i==container[ch].parent ) {
   1.223 +            i=ch;
   1.224 +            //break;
   1.225 +          } else {
   1.226 +            if( container[ch].left_child ) {
   1.227 +              child_right=container[ch].parent;
   1.228 +              container[ch].parent = i;
   1.229 +              --container[i].degree;
   1.230 +            }
   1.231 +            else {
   1.232 +              child_right=ch;
   1.233 +              container[i].child=-1;
   1.234 +              container[i].degree=0;
   1.235 +            }
   1.236 +            container[child_right].parent = -1;
   1.237 +            TreeArray[num_child] = child_right;
   1.238 +            i = child_right;
   1.239 +            ++num_child;
   1.240 +          }
   1.241 +        }
   1.242 +
   1.243 +        int other;
   1.244 +        for( i=0; i<num_child-1; i+=2 ) {
   1.245 +          if ( !comp(container[TreeArray[i]].prio,
   1.246 +                     container[TreeArray[i+1]].prio) ) {
   1.247 +            other=TreeArray[i];
   1.248 +            TreeArray[i]=TreeArray[i+1];
   1.249 +            TreeArray[i+1]=other;
   1.250 +          }
   1.251 +          fuse( TreeArray[i], TreeArray[i+1] );
   1.252 +        }
   1.253 +
   1.254 +        i = (0==(num_child % 2)) ? num_child-2 : num_child-1;
   1.255 +        while(i>=2) {
   1.256 +          if ( comp(container[TreeArray[i]].prio,
   1.257 +                    container[TreeArray[i-2]].prio) ) {
   1.258 +            other=TreeArray[i];
   1.259 +            TreeArray[i]=TreeArray[i-2];
   1.260 +            TreeArray[i-2]=other;
   1.261 +          }
   1.262 +          fuse( TreeArray[i-2], TreeArray[i] );
   1.263 +          i-=2;
   1.264 +        }
   1.265 +        minimum = TreeArray[0];
   1.266 +      }
   1.267 +
   1.268 +      if ( 0==num_child ) {
   1.269 +        minimum = container[minimum].child;
   1.270 +      }
   1.271 +
   1.272 +      --num_items;
   1.273 +    }
   1.274 +
   1.275 +    /// \brief Deletes \c item from the heap.
   1.276 +    ///
   1.277 +    /// This method deletes \c item from the heap, if \c item was already
   1.278 +    /// stored in the heap. It is quite inefficient in Pairing heaps.
   1.279 +    void erase (const Item& item) {
   1.280 +      int i=iimap[item];
   1.281 +      if ( i>=0 && container[i].in ) {
   1.282 +        decrease( item, container[minimum].prio-1 );
   1.283 +        pop();
   1.284 +      }
   1.285 +    }
   1.286 +
   1.287 +    /// \brief Decreases the priority of \c item to \c value.
   1.288 +    ///
   1.289 +    /// This method decreases the priority of \c item to \c value.
   1.290 +    /// \pre \c item must be stored in the heap with priority at least \c
   1.291 +    ///   value relative to \c Compare.
   1.292 +    void decrease (Item item, const Prio& value) {
   1.293 +      int i=iimap[item];
   1.294 +      container[i].prio=value;
   1.295 +      int p=container[i].parent;
   1.296 +
   1.297 +      if( container[i].left_child && i!=container[p].child ) {
   1.298 +        p=container[p].parent;
   1.299 +      }
   1.300 +
   1.301 +      if ( p!=-1 && comp(value,container[p].prio) ) {
   1.302 +        cut(i,p);
   1.303 +        if ( comp(container[minimum].prio,value) ) {
   1.304 +          fuse(minimum,i);
   1.305 +        } else {
   1.306 +          fuse(i,minimum);
   1.307 +          minimum=i;
   1.308 +        }
   1.309 +      }
   1.310 +    }
   1.311 +
   1.312 +    /// \brief Increases the priority of \c item to \c value.
   1.313 +    ///
   1.314 +    /// This method sets the priority of \c item to \c value. Though
   1.315 +    /// there is no precondition on the priority of \c item, this
   1.316 +    /// method should be used only if it is indeed necessary to increase
   1.317 +    /// (relative to \c Compare) the priority of \c item, because this
   1.318 +    /// method is inefficient.
   1.319 +    void increase (Item item, const Prio& value) {
   1.320 +      erase(item);
   1.321 +      push(item,value);
   1.322 +    }
   1.323 +
   1.324 +    /// \brief Returns if \c item is in, has already been in, or has never
   1.325 +    /// been in the heap.
   1.326 +    ///
   1.327 +    /// This method returns PRE_HEAP if \c item has never been in the
   1.328 +    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
   1.329 +    /// otherwise. In the latter case it is possible that \c item will
   1.330 +    /// get back to the heap again.
   1.331 +    State state(const Item &item) const {
   1.332 +      int i=iimap[item];
   1.333 +      if( i>=0 ) {
   1.334 +        if( container[i].in ) i=0;
   1.335 +        else i=-2;
   1.336 +      }
   1.337 +      return State(i);
   1.338 +    }
   1.339 +
   1.340 +    /// \brief Sets the state of the \c item in the heap.
   1.341 +    ///
   1.342 +    /// Sets the state of the \c item in the heap. It can be used to
   1.343 +    /// manually clear the heap when it is important to achive the
   1.344 +    /// better time complexity.
   1.345 +    /// \param i The item.
   1.346 +    /// \param st The state. It should not be \c IN_HEAP.
   1.347 +    void state(const Item& i, State st) {
   1.348 +      switch (st) {
   1.349 +      case POST_HEAP:
   1.350 +      case PRE_HEAP:
   1.351 +        if (state(i) == IN_HEAP) erase(i);
   1.352 +        iimap[i]=st;
   1.353 +        break;
   1.354 +      case IN_HEAP:
   1.355 +        break;
   1.356 +      }
   1.357 +    }
   1.358 +
   1.359 +  private:
   1.360 +
   1.361 +    void cut(int a, int b) {
   1.362 +      int child_a;
   1.363 +      switch (container[a].degree) {
   1.364 +        case 2:
   1.365 +          child_a = container[container[a].child].parent;
   1.366 +          if( container[a].left_child ) {
   1.367 +            container[child_a].left_child=true;
   1.368 +            container[b].child=child_a;
   1.369 +            container[child_a].parent=container[a].parent;
   1.370 +          }
   1.371 +          else {
   1.372 +            container[child_a].left_child=false;
   1.373 +            container[child_a].parent=b;
   1.374 +            if( a!=container[b].child )
   1.375 +              container[container[b].child].parent=child_a;
   1.376 +            else
   1.377 +              container[b].child=child_a;
   1.378 +          }
   1.379 +          --container[a].degree;
   1.380 +          container[container[a].child].parent=a;
   1.381 +          break;
   1.382 +
   1.383 +        case 1:
   1.384 +          child_a = container[a].child;
   1.385 +          if( !container[child_a].left_child ) {
   1.386 +            --container[a].degree;
   1.387 +            if( container[a].left_child ) {
   1.388 +              container[child_a].left_child=true;
   1.389 +              container[child_a].parent=container[a].parent;
   1.390 +              container[b].child=child_a;
   1.391 +            }
   1.392 +            else {
   1.393 +              container[child_a].left_child=false;
   1.394 +              container[child_a].parent=b;
   1.395 +              if( a!=container[b].child )
   1.396 +                container[container[b].child].parent=child_a;
   1.397 +              else
   1.398 +                container[b].child=child_a;
   1.399 +            }
   1.400 +            container[a].child=-1;
   1.401 +          }
   1.402 +          else {
   1.403 +            --container[b].degree;
   1.404 +            if( container[a].left_child ) {
   1.405 +              container[b].child =
   1.406 +                (1==container[b].degree) ? container[a].parent : -1;
   1.407 +            } else {
   1.408 +              if (1==container[b].degree)
   1.409 +                container[container[b].child].parent=b;
   1.410 +              else
   1.411 +                container[b].child=-1;
   1.412 +            }
   1.413 +          }
   1.414 +          break;
   1.415 +
   1.416 +        case 0:
   1.417 +          --container[b].degree;
   1.418 +          if( container[a].left_child ) {
   1.419 +            container[b].child =
   1.420 +              (0!=container[b].degree) ? container[a].parent : -1;
   1.421 +          } else {
   1.422 +            if( 0!=container[b].degree )
   1.423 +              container[container[b].child].parent=b;
   1.424 +            else
   1.425 +              container[b].child=-1;
   1.426 +          }
   1.427 +          break;
   1.428 +      }
   1.429 +      container[a].parent=-1;
   1.430 +      container[a].left_child=false;
   1.431 +    }
   1.432 +
   1.433 +    void fuse(int a, int b) {
   1.434 +      int child_a = container[a].child;
   1.435 +      int child_b = container[b].child;
   1.436 +      container[a].child=b;
   1.437 +      container[b].parent=a;
   1.438 +      container[b].left_child=true;
   1.439 +
   1.440 +      if( -1!=child_a ) {
   1.441 +        container[b].child=child_a;
   1.442 +        container[child_a].parent=b;
   1.443 +        container[child_a].left_child=false;
   1.444 +        ++container[b].degree;
   1.445 +
   1.446 +        if( -1!=child_b ) {
   1.447 +           container[b].child=child_b;
   1.448 +           container[child_b].parent=child_a;
   1.449 +        }
   1.450 +      }
   1.451 +      else { ++container[a].degree; }
   1.452 +    }
   1.453 +
   1.454 +    class store {
   1.455 +      friend class PairingHeap;
   1.456 +
   1.457 +      Item name;
   1.458 +      int parent;
   1.459 +      int child;
   1.460 +      bool left_child;
   1.461 +      int degree;
   1.462 +      bool in;
   1.463 +      Prio prio;
   1.464 +
   1.465 +      store() : parent(-1), child(-1), left_child(false), degree(0), in(true) {}
   1.466 +    };
   1.467 +  };
   1.468 +
   1.469 +} //namespace lemon
   1.470 +
   1.471 +#endif //LEMON_PAIRING_HEAP_H
   1.472 +