kpeter@701: /* -*- C++ -*- kpeter@701: * kpeter@701: * This file is a part of LEMON, a generic C++ optimization library kpeter@701: * kpeter@701: * Copyright (C) 2003-2008 kpeter@701: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport kpeter@701: * (Egervary Research Group on Combinatorial Optimization, EGRES). kpeter@701: * kpeter@701: * Permission to use, modify and distribute this software is granted kpeter@701: * provided that this copyright notice appears in all copies. For kpeter@701: * precise terms see the accompanying LICENSE file. kpeter@701: * kpeter@701: * This software is provided "AS IS" with no warranty of any kind, kpeter@701: * express or implied, and with no claim as to its suitability for any kpeter@701: * purpose. kpeter@701: * kpeter@701: */ kpeter@701: kpeter@701: #ifndef LEMON_BINOM_HEAP_H kpeter@701: #define LEMON_BINOM_HEAP_H kpeter@701: kpeter@701: ///\file kpeter@701: ///\ingroup auxdat kpeter@701: ///\brief Binomial Heap implementation. kpeter@701: kpeter@701: #include kpeter@701: #include kpeter@701: #include kpeter@701: #include kpeter@701: kpeter@701: namespace lemon { kpeter@701: kpeter@701: /// \ingroup auxdat kpeter@701: /// kpeter@701: ///\brief Binomial Heap. kpeter@701: /// kpeter@701: ///This class implements the \e Binomial \e heap data structure. A \e heap kpeter@701: ///is a data structure for storing items with specified values called \e kpeter@701: ///priorities in such a way that finding the item with minimum priority is kpeter@701: ///efficient. \c Compare specifies the ordering of the priorities. In a heap kpeter@701: ///one can change the priority of an item, add or erase an item, etc. kpeter@701: /// kpeter@701: ///The methods \ref increase and \ref erase are not efficient in a Binomial kpeter@701: ///heap. In case of many calls to these operations, it is better to use a kpeter@701: ///\ref BinHeap "binary heap". kpeter@701: /// kpeter@701: ///\param _Prio Type of the priority of the items. kpeter@701: ///\param _ItemIntMap A read and writable Item int map, used internally kpeter@701: ///to handle the cross references. kpeter@701: ///\param _Compare A class for the ordering of the priorities. The kpeter@701: ///default is \c std::less<_Prio>. kpeter@701: /// kpeter@701: ///\sa BinHeap kpeter@701: ///\sa Dijkstra kpeter@701: ///\author Dorian Batha kpeter@701: kpeter@701: #ifdef DOXYGEN kpeter@701: template kpeter@701: #else kpeter@701: template > kpeter@701: #endif kpeter@701: class BinomHeap { kpeter@701: public: kpeter@701: typedef _ItemIntMap ItemIntMap; kpeter@701: typedef _Prio Prio; kpeter@701: typedef typename ItemIntMap::Key Item; kpeter@701: typedef std::pair Pair; kpeter@701: typedef _Compare Compare; kpeter@701: kpeter@701: private: kpeter@701: class store; kpeter@701: kpeter@701: std::vector container; kpeter@701: int minimum, head; kpeter@701: ItemIntMap &iimap; kpeter@701: Compare comp; kpeter@701: int num_items; kpeter@701: kpeter@701: public: kpeter@701: ///Status of the nodes kpeter@701: enum State { kpeter@701: ///The node is in the heap kpeter@701: IN_HEAP = 0, kpeter@701: ///The node has never been in the heap kpeter@701: PRE_HEAP = -1, kpeter@701: ///The node was in the heap but it got out of it kpeter@701: POST_HEAP = -2 kpeter@701: }; kpeter@701: kpeter@701: /// \brief The constructor kpeter@701: /// kpeter@701: /// \c _iimap should be given to the constructor, since it is kpeter@701: /// used internally to handle the cross references. kpeter@701: explicit BinomHeap(ItemIntMap &_iimap) kpeter@701: : minimum(0), head(-1), iimap(_iimap), num_items() {} kpeter@701: kpeter@701: /// \brief The constructor kpeter@701: /// kpeter@701: /// \c _iimap should be given to the constructor, since it is used kpeter@701: /// internally to handle the cross references. \c _comp is an kpeter@701: /// object for ordering of the priorities. kpeter@701: BinomHeap(ItemIntMap &_iimap, const Compare &_comp) kpeter@701: : minimum(0), head(-1), iimap(_iimap), comp(_comp), num_items() {} kpeter@701: kpeter@701: /// \brief The number of items stored in the heap. kpeter@701: /// kpeter@701: /// Returns the number of items stored in the heap. kpeter@701: int size() const { return num_items; } kpeter@701: kpeter@701: /// \brief Checks if the heap stores no items. kpeter@701: /// kpeter@701: /// Returns \c true if and only if the heap stores no items. kpeter@701: bool empty() const { return num_items==0; } kpeter@701: kpeter@701: /// \brief Make empty this heap. kpeter@701: /// kpeter@701: /// Make empty this heap. It does not change the cross reference kpeter@701: /// map. If you want to reuse a heap what is not surely empty you kpeter@701: /// should first clear the heap and after that you should set the kpeter@701: /// cross reference map for each item to \c PRE_HEAP. kpeter@701: void clear() { kpeter@701: container.clear(); minimum=0; num_items=0; head=-1; kpeter@701: } kpeter@701: kpeter@701: /// \brief \c item gets to the heap with priority \c value independently kpeter@701: /// if \c item was already there. kpeter@701: /// kpeter@701: /// This method calls \ref push(\c item, \c value) if \c item is not kpeter@701: /// stored in the heap and it calls \ref decrease(\c item, \c value) or kpeter@701: /// \ref increase(\c item, \c value) otherwise. kpeter@701: void set (const Item& item, const Prio& value) { kpeter@701: int i=iimap[item]; kpeter@701: if ( i >= 0 && container[i].in ) { kpeter@701: if ( comp(value, container[i].prio) ) decrease(item, value); kpeter@701: if ( comp(container[i].prio, value) ) increase(item, value); kpeter@701: } else push(item, value); kpeter@701: } kpeter@701: kpeter@701: /// \brief Adds \c item to the heap with priority \c value. kpeter@701: /// kpeter@701: /// Adds \c item to the heap with priority \c value. kpeter@701: /// \pre \c item must not be stored in the heap. kpeter@701: void push (const Item& item, const Prio& value) { kpeter@701: int i=iimap[item]; kpeter@701: if ( i<0 ) { kpeter@701: int s=container.size(); kpeter@701: iimap.set( item,s ); kpeter@701: store st; kpeter@701: st.name=item; kpeter@701: container.push_back(st); kpeter@701: i=s; kpeter@701: } kpeter@701: else { kpeter@701: container[i].parent=container[i].right_neighbor=container[i].child=-1; kpeter@701: container[i].degree=0; kpeter@701: container[i].in=true; kpeter@701: } kpeter@701: container[i].prio=value; kpeter@701: kpeter@701: if( 0==num_items ) { head=i; minimum=i; } kpeter@701: else { merge(i); } kpeter@701: kpeter@701: minimum = find_min(); kpeter@701: kpeter@701: ++num_items; kpeter@701: } kpeter@701: kpeter@701: /// \brief Returns the item with minimum priority relative to \c Compare. kpeter@701: /// kpeter@701: /// This method returns the item with minimum priority relative to \c kpeter@701: /// Compare. kpeter@701: /// \pre The heap must be nonempty. kpeter@701: Item top() const { return container[minimum].name; } kpeter@701: kpeter@701: /// \brief Returns the minimum priority relative to \c Compare. kpeter@701: /// kpeter@701: /// It returns the minimum priority relative to \c Compare. kpeter@701: /// \pre The heap must be nonempty. kpeter@701: const Prio& prio() const { return container[minimum].prio; } kpeter@701: kpeter@701: /// \brief Returns the priority of \c item. kpeter@701: /// kpeter@701: /// It returns the priority of \c item. kpeter@701: /// \pre \c item must be in the heap. kpeter@701: const Prio& operator[](const Item& item) const { kpeter@701: return container[iimap[item]].prio; kpeter@701: } kpeter@701: kpeter@701: /// \brief Deletes the item with minimum priority relative to \c Compare. kpeter@701: /// kpeter@701: /// This method deletes the item with minimum priority relative to \c kpeter@701: /// Compare from the heap. kpeter@701: /// \pre The heap must be non-empty. kpeter@701: void pop() { kpeter@701: container[minimum].in=false; kpeter@701: kpeter@701: int head_child=-1; kpeter@701: if ( container[minimum].child!=-1 ) { kpeter@701: int child=container[minimum].child; kpeter@701: int neighb; kpeter@701: int prev=-1; kpeter@701: while( child!=-1 ) { kpeter@701: neighb=container[child].right_neighbor; kpeter@701: container[child].parent=-1; kpeter@701: container[child].right_neighbor=prev; kpeter@701: head_child=child; kpeter@701: prev=child; kpeter@701: child=neighb; kpeter@701: } kpeter@701: } kpeter@701: kpeter@701: // The first case is that there are only one root. kpeter@701: if ( -1==container[head].right_neighbor ) { kpeter@701: head=head_child; kpeter@701: } kpeter@701: // The case where there are more roots. kpeter@701: else { kpeter@701: if( head!=minimum ) { unlace(minimum); } kpeter@701: else { head=container[head].right_neighbor; } kpeter@701: kpeter@701: merge(head_child); kpeter@701: } kpeter@701: minimum=find_min(); kpeter@701: --num_items; kpeter@701: } kpeter@701: kpeter@701: /// \brief Deletes \c item from the heap. kpeter@701: /// kpeter@701: /// This method deletes \c item from the heap, if \c item was already kpeter@701: /// stored in the heap. It is quite inefficient in Binomial heaps. kpeter@701: void erase (const Item& item) { kpeter@701: int i=iimap[item]; kpeter@701: if ( i >= 0 && container[i].in ) { kpeter@701: decrease( item, container[minimum].prio-1 ); kpeter@701: pop(); kpeter@701: } kpeter@701: } kpeter@701: kpeter@701: /// \brief Decreases the priority of \c item to \c value. kpeter@701: /// kpeter@701: /// This method decreases the priority of \c item to \c value. kpeter@701: /// \pre \c item must be stored in the heap with priority at least \c kpeter@701: /// value relative to \c Compare. kpeter@701: void decrease (Item item, const Prio& value) { kpeter@701: int i=iimap[item]; kpeter@701: kpeter@701: if( comp( value,container[i].prio ) ) { kpeter@701: container[i].prio=value; kpeter@701: kpeter@701: int p_loc=container[i].parent, loc=i; kpeter@701: int parent, child, neighb; kpeter@701: kpeter@701: while( -1!=p_loc && comp(container[loc].prio,container[p_loc].prio) ) { kpeter@701: kpeter@701: // parent set for other loc_child kpeter@701: child=container[loc].child; kpeter@701: while( -1!=child ) { kpeter@701: container[child].parent=p_loc; kpeter@701: child=container[child].right_neighbor; kpeter@701: } kpeter@701: kpeter@701: // parent set for other p_loc_child kpeter@701: child=container[p_loc].child; kpeter@701: while( -1!=child ) { kpeter@701: container[child].parent=loc; kpeter@701: child=container[child].right_neighbor; kpeter@701: } kpeter@701: kpeter@701: child=container[p_loc].child; kpeter@701: container[p_loc].child=container[loc].child; kpeter@701: if( child==loc ) kpeter@701: child=p_loc; kpeter@701: container[loc].child=child; kpeter@701: kpeter@701: // left_neighb set for p_loc kpeter@701: if( container[loc].child!=p_loc ) { kpeter@701: while( container[child].right_neighbor!=loc ) kpeter@701: child=container[child].right_neighbor; kpeter@701: container[child].right_neighbor=p_loc; kpeter@701: } kpeter@701: kpeter@701: // left_neighb set for loc kpeter@701: parent=container[p_loc].parent; kpeter@701: if( -1!=parent ) child=container[parent].child; kpeter@701: else child=head; kpeter@701: kpeter@701: if( child!=p_loc ) { kpeter@701: while( container[child].right_neighbor!=p_loc ) kpeter@701: child=container[child].right_neighbor; kpeter@701: container[child].right_neighbor=loc; kpeter@701: } kpeter@701: kpeter@701: neighb=container[p_loc].right_neighbor; kpeter@701: container[p_loc].right_neighbor=container[loc].right_neighbor; kpeter@701: container[loc].right_neighbor=neighb; kpeter@701: kpeter@701: container[p_loc].parent=loc; kpeter@701: container[loc].parent=parent; kpeter@701: kpeter@701: if( -1!=parent && container[parent].child==p_loc ) kpeter@701: container[parent].child=loc; kpeter@701: kpeter@701: /*if new parent will be the first root*/ kpeter@701: if( head==p_loc ) kpeter@701: head=loc; kpeter@701: kpeter@701: p_loc=container[loc].parent; kpeter@701: } kpeter@701: } kpeter@701: if( comp(value,container[minimum].prio) ) { kpeter@701: minimum=i; kpeter@701: } kpeter@701: } kpeter@701: kpeter@701: /// \brief Increases the priority of \c item to \c value. kpeter@701: /// kpeter@701: /// This method sets the priority of \c item to \c value. Though kpeter@701: /// there is no precondition on the priority of \c item, this kpeter@701: /// method should be used only if it is indeed necessary to increase kpeter@701: /// (relative to \c Compare) the priority of \c item, because this kpeter@701: /// method is inefficient. kpeter@701: void increase (Item item, const Prio& value) { kpeter@701: erase(item); kpeter@701: push(item, value); kpeter@701: } kpeter@701: kpeter@701: kpeter@701: /// \brief Returns if \c item is in, has already been in, or has never kpeter@701: /// been in the heap. kpeter@701: /// kpeter@701: /// This method returns PRE_HEAP if \c item has never been in the kpeter@701: /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP kpeter@701: /// otherwise. In the latter case it is possible that \c item will kpeter@701: /// get back to the heap again. kpeter@701: State state(const Item &item) const { kpeter@701: int i=iimap[item]; kpeter@701: if( i>=0 ) { kpeter@701: if ( container[i].in ) i=0; kpeter@701: else i=-2; kpeter@701: } kpeter@701: return State(i); kpeter@701: } kpeter@701: kpeter@701: /// \brief Sets the state of the \c item in the heap. kpeter@701: /// kpeter@701: /// Sets the state of the \c item in the heap. It can be used to kpeter@701: /// manually clear the heap when it is important to achive the kpeter@701: /// better time complexity. kpeter@701: /// \param i The item. kpeter@701: /// \param st The state. It should not be \c IN_HEAP. kpeter@701: void state(const Item& i, State st) { kpeter@701: switch (st) { kpeter@701: case POST_HEAP: kpeter@701: case PRE_HEAP: kpeter@701: if (state(i) == IN_HEAP) { kpeter@701: erase(i); kpeter@701: } kpeter@701: iimap[i] = st; kpeter@701: break; kpeter@701: case IN_HEAP: kpeter@701: break; kpeter@701: } kpeter@701: } kpeter@701: kpeter@701: private: kpeter@701: int find_min() { kpeter@701: int min_loc=-1, min_val; kpeter@701: int x=head; kpeter@701: if( x!=-1 ) { kpeter@701: min_val=container[x].prio; kpeter@701: min_loc=x; kpeter@701: x=container[x].right_neighbor; kpeter@701: kpeter@701: while( x!=-1 ) { kpeter@701: if( comp( container[x].prio,min_val ) ) { kpeter@701: min_val=container[x].prio; kpeter@701: min_loc=x; kpeter@701: } kpeter@701: x=container[x].right_neighbor; kpeter@701: } kpeter@701: } kpeter@701: return min_loc; kpeter@701: } kpeter@701: kpeter@701: void merge(int a) { kpeter@701: interleave(a); kpeter@701: kpeter@701: int x=head; kpeter@701: if( -1!=x ) { kpeter@701: int x_prev=-1, x_next=container[x].right_neighbor; kpeter@701: while( -1!=x_next ) { kpeter@701: if( container[x].degree!=container[x_next].degree || ( -1!=container[x_next].right_neighbor && container[container[x_next].right_neighbor].degree==container[x].degree ) ) { kpeter@701: x_prev=x; kpeter@701: x=x_next; kpeter@701: } kpeter@701: else { kpeter@701: if( comp(container[x].prio,container[x_next].prio) ) { kpeter@701: container[x].right_neighbor=container[x_next].right_neighbor; kpeter@701: fuse(x_next,x); kpeter@701: } kpeter@701: else { kpeter@701: if( -1==x_prev ) { head=x_next; } kpeter@701: else { kpeter@701: container[x_prev].right_neighbor=x_next; kpeter@701: } kpeter@701: fuse(x,x_next); kpeter@701: x=x_next; kpeter@701: } kpeter@701: } kpeter@701: x_next=container[x].right_neighbor; kpeter@701: } kpeter@701: } kpeter@701: } kpeter@701: kpeter@701: void interleave(int a) { kpeter@701: int other=-1, head_other=-1; kpeter@701: kpeter@701: while( -1!=a || -1!=head ) { kpeter@701: if( -1==a ) { kpeter@701: if( -1==head_other ) { kpeter@701: head_other=head; kpeter@701: } kpeter@701: else { kpeter@701: container[other].right_neighbor=head; kpeter@701: } kpeter@701: head=-1; kpeter@701: } kpeter@701: else if( -1==head ) { kpeter@701: if( -1==head_other ) { kpeter@701: head_other=a; kpeter@701: } kpeter@701: else { kpeter@701: container[other].right_neighbor=a; kpeter@701: } kpeter@701: a=-1; kpeter@701: } kpeter@701: else { kpeter@701: if( container[a].degree