alpar@100: /* -*- C++ -*- alpar@100: * alpar@100: * This file is a part of LEMON, a generic C++ optimization library alpar@100: * alpar@100: * Copyright (C) 2003-2008 alpar@100: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@100: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@100: * alpar@100: * Permission to use, modify and distribute this software is granted alpar@100: * provided that this copyright notice appears in all copies. For alpar@100: * precise terms see the accompanying LICENSE file. alpar@100: * alpar@100: * This software is provided "AS IS" with no warranty of any kind, alpar@100: * express or implied, and with no claim as to its suitability for any alpar@100: * purpose. alpar@100: * alpar@100: */ alpar@100: alpar@100: #ifndef LEMON_BIN_HEAP_H alpar@100: #define LEMON_BIN_HEAP_H alpar@100: alpar@100: ///\ingroup auxdat alpar@100: ///\file alpar@100: ///\brief Binary Heap implementation. alpar@100: alpar@100: #include alpar@100: #include alpar@100: #include alpar@100: alpar@100: namespace lemon { alpar@100: alpar@100: ///\ingroup auxdat alpar@100: /// alpar@100: ///\brief A Binary Heap implementation. alpar@100: /// alpar@100: ///This class implements the \e binary \e heap data structure. A \e heap alpar@100: ///is a data structure for storing items with specified values called \e alpar@100: ///priorities in such a way that finding the item with minimum priority is alpar@100: ///efficient. \c Compare specifies the ordering of the priorities. In a heap alpar@100: ///one can change the priority of an item, add or erase an item, etc. alpar@100: /// alpar@100: ///\param _Prio Type of the priority of the items. alpar@100: ///\param _ItemIntMap A read and writable Item int map, used internally alpar@100: ///to handle the cross references. alpar@100: ///\param _Compare A class for the ordering of the priorities. The alpar@100: ///default is \c std::less<_Prio>. alpar@100: /// alpar@100: ///\sa FibHeap alpar@100: ///\sa Dijkstra alpar@100: template > alpar@100: class BinHeap { alpar@100: alpar@100: public: alpar@100: ///\e alpar@100: typedef _ItemIntMap ItemIntMap; alpar@100: ///\e alpar@100: typedef _Prio Prio; alpar@100: ///\e alpar@100: typedef typename ItemIntMap::Key Item; alpar@100: ///\e alpar@100: typedef std::pair Pair; alpar@100: ///\e alpar@100: typedef _Compare Compare; alpar@100: alpar@100: /// \brief Type to represent the items states. alpar@100: /// alpar@100: /// Each Item element have a state associated to it. It may be "in heap", alpar@100: /// "pre heap" or "post heap". The latter two are indifferent from the alpar@100: /// heap's point of view, but may be useful to the user. alpar@100: /// alpar@100: /// The ItemIntMap \e should be initialized in such way that it maps alpar@100: /// PRE_HEAP (-1) to any element to be put in the heap... alpar@100: enum State { alpar@100: IN_HEAP = 0, alpar@100: PRE_HEAP = -1, alpar@100: POST_HEAP = -2 alpar@100: }; alpar@100: alpar@100: private: alpar@100: std::vector data; alpar@100: Compare comp; alpar@100: ItemIntMap &iim; alpar@100: alpar@100: public: alpar@100: /// \brief The constructor. alpar@100: /// alpar@100: /// The constructor. alpar@100: /// \param _iim should be given to the constructor, since it is used alpar@100: /// internally to handle the cross references. The value of the map alpar@100: /// should be PRE_HEAP (-1) for each element. alpar@100: explicit BinHeap(ItemIntMap &_iim) : iim(_iim) {} alpar@100: alpar@100: /// \brief The constructor. alpar@100: /// alpar@100: /// The constructor. alpar@100: /// \param _iim should be given to the constructor, since it is used alpar@100: /// internally to handle the cross references. The value of the map alpar@100: /// should be PRE_HEAP (-1) for each element. alpar@100: /// alpar@100: /// \param _comp The comparator function object. alpar@100: BinHeap(ItemIntMap &_iim, const Compare &_comp) alpar@100: : iim(_iim), comp(_comp) {} alpar@100: alpar@100: alpar@100: /// The number of items stored in the heap. alpar@100: /// alpar@100: /// \brief Returns the number of items stored in the heap. alpar@100: int size() const { return data.size(); } alpar@100: alpar@100: /// \brief Checks if the heap stores no items. alpar@100: /// alpar@100: /// Returns \c true if and only if the heap stores no items. alpar@100: bool empty() const { return data.empty(); } alpar@100: alpar@100: /// \brief Make empty this heap. alpar@100: /// alpar@100: /// Make empty this heap. It does not change the cross reference map. alpar@100: /// If you want to reuse what is not surely empty you should first clear alpar@100: /// the heap and after that you should set the cross reference map for alpar@100: /// each item to \c PRE_HEAP. alpar@100: void clear() { alpar@100: data.clear(); alpar@100: } alpar@100: alpar@100: private: alpar@100: static int parent(int i) { return (i-1)/2; } alpar@100: alpar@100: static int second_child(int i) { return 2*i+2; } alpar@100: bool less(const Pair &p1, const Pair &p2) const { alpar@100: return comp(p1.second, p2.second); alpar@100: } alpar@100: alpar@100: int bubble_up(int hole, Pair p) { alpar@100: int par = parent(hole); alpar@100: while( hole>0 && less(p,data[par]) ) { alpar@100: move(data[par],hole); alpar@100: hole = par; alpar@100: par = parent(hole); alpar@100: } alpar@100: move(p, hole); alpar@100: return hole; alpar@100: } alpar@100: alpar@100: int bubble_down(int hole, Pair p, int length) { alpar@100: int child = second_child(hole); alpar@100: while(child < length) { alpar@100: if( less(data[child-1], data[child]) ) { alpar@100: --child; alpar@100: } alpar@100: if( !less(data[child], p) ) alpar@100: goto ok; alpar@100: move(data[child], hole); alpar@100: hole = child; alpar@100: child = second_child(hole); alpar@100: } alpar@100: child--; alpar@100: if( child 0) { alpar@100: bubble_down(0, data[n], n); alpar@100: } alpar@100: data.pop_back(); alpar@100: } alpar@100: alpar@100: /// \brief Deletes \c i from the heap. alpar@100: /// alpar@100: /// This method deletes item \c i from the heap. alpar@100: /// \param i The item to erase. alpar@100: /// \pre The item should be in the heap. alpar@100: void erase(const Item &i) { alpar@100: int h = iim[i]; alpar@100: int n = data.size()-1; alpar@100: iim.set(data[h].first, POST_HEAP); alpar@100: if( h < n ) { alpar@100: if ( bubble_up(h, data[n]) == h) { alpar@100: bubble_down(h, data[n], n); alpar@100: } alpar@100: } alpar@100: data.pop_back(); alpar@100: } alpar@100: alpar@100: alpar@100: /// \brief Returns the priority of \c i. alpar@100: /// alpar@100: /// This function returns the priority of item \c i. alpar@100: /// \pre \c i must be in the heap. alpar@100: /// \param i The item. alpar@100: Prio operator[](const Item &i) const { alpar@100: int idx = iim[i]; alpar@100: return data[idx].second; alpar@100: } alpar@100: alpar@100: /// \brief \c i gets to the heap with priority \c p independently alpar@100: /// if \c i was already there. alpar@100: /// alpar@100: /// This method calls \ref push(\c i, \c p) if \c i is not stored alpar@100: /// in the heap and sets the priority of \c i to \c p otherwise. alpar@100: /// \param i The item. alpar@100: /// \param p The priority. alpar@100: void set(const Item &i, const Prio &p) { alpar@100: int idx = iim[i]; alpar@100: if( idx < 0 ) { alpar@100: push(i,p); alpar@100: } alpar@100: else if( comp(p, data[idx].second) ) { alpar@100: bubble_up(idx, Pair(i,p)); alpar@100: } alpar@100: else { alpar@100: bubble_down(idx, Pair(i,p), data.size()); alpar@100: } alpar@100: } alpar@100: alpar@100: /// \brief Decreases the priority of \c i to \c p. alpar@100: /// alpar@100: /// This method decreases the priority of item \c i to \c p. alpar@100: /// \pre \c i must be stored in the heap with priority at least \c alpar@100: /// p relative to \c Compare. alpar@100: /// \param i The item. alpar@100: /// \param p The priority. alpar@100: void decrease(const Item &i, const Prio &p) { alpar@100: int idx = iim[i]; alpar@100: bubble_up(idx, Pair(i,p)); alpar@100: } alpar@100: alpar@100: /// \brief Increases the priority of \c i to \c p. alpar@100: /// alpar@100: /// This method sets the priority of item \c i to \c p. alpar@100: /// \pre \c i must be stored in the heap with priority at most \c alpar@100: /// p relative to \c Compare. alpar@100: /// \param i The item. alpar@100: /// \param p The priority. alpar@100: void increase(const Item &i, const Prio &p) { alpar@100: int idx = iim[i]; alpar@100: bubble_down(idx, Pair(i,p), data.size()); alpar@100: } alpar@100: alpar@100: /// \brief Returns if \c item is in, has already been in, or has alpar@100: /// never been in the heap. alpar@100: /// alpar@100: /// This method returns PRE_HEAP if \c item has never been in the alpar@100: /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP alpar@100: /// otherwise. In the latter case it is possible that \c item will alpar@100: /// get back to the heap again. alpar@100: /// \param i The item. alpar@100: State state(const Item &i) const { alpar@100: int s = iim[i]; alpar@100: if( s>=0 ) alpar@100: s=0; alpar@100: return State(s); alpar@100: } alpar@100: alpar@100: /// \brief Sets the state of the \c item in the heap. alpar@100: /// alpar@100: /// Sets the state of the \c item in the heap. It can be used to alpar@100: /// manually clear the heap when it is important to achive the alpar@100: /// better time complexity. alpar@100: /// \param i The item. alpar@100: /// \param st The state. It should not be \c IN_HEAP. alpar@100: void state(const Item& i, State st) { alpar@100: switch (st) { alpar@100: case POST_HEAP: alpar@100: case PRE_HEAP: alpar@100: if (state(i) == IN_HEAP) { alpar@100: erase(i); alpar@100: } alpar@100: iim[i] = st; alpar@100: break; alpar@100: case IN_HEAP: alpar@100: break; alpar@100: } alpar@100: } alpar@100: alpar@100: /// \brief Replaces an item in the heap. alpar@100: /// alpar@100: /// The \c i item is replaced with \c j item. The \c i item should alpar@100: /// be in the heap, while the \c j should be out of the heap. The alpar@100: /// \c i item will out of the heap and \c j will be in the heap alpar@100: /// with the same prioriority as prevoiusly the \c i item. alpar@100: void replace(const Item& i, const Item& j) { alpar@100: int idx = iim[i]; alpar@100: iim.set(i, iim[j]); alpar@100: iim.set(j, idx); alpar@100: data[idx].first = j; alpar@100: } alpar@100: alpar@100: }; // class BinHeap alpar@100: alpar@100: } // namespace lemon alpar@100: alpar@100: #endif // LEMON_BIN_HEAP_H