alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@100: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. alpar@100: * alpar@463: * Copyright (C) 2003-2009 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@1064: ///This class implements the \e binary \e heap data structure. alpar@1064: /// kpeter@606: ///A \e heap is a data structure for storing items with specified values kpeter@606: ///called \e priorities in such a way that finding the item with minimum alpar@1064: ///priority is efficient. \c CMP specifies the ordering of the priorities. kpeter@606: ///In a heap one can change the priority of an item, add or erase an kpeter@606: ///item, etc. alpar@100: /// kpeter@606: ///\tparam PR Type of the priority of the items. kpeter@606: ///\tparam IM A read and writable item map with int values, used internally alpar@100: ///to handle the cross references. alpar@1064: ///\tparam CMP A functor class for the ordering of the priorities. kpeter@606: ///The default is \c std::less. alpar@100: /// alpar@100: ///\sa FibHeap alpar@100: ///\sa Dijkstra alpar@1064: template > alpar@100: class BinHeap { alpar@100: alpar@100: public: alpar@100: ///\e kpeter@606: typedef IM ItemIntMap; alpar@100: ///\e kpeter@606: typedef PR Prio; alpar@100: ///\e alpar@100: typedef typename ItemIntMap::Key Item; alpar@100: ///\e alpar@100: typedef std::pair Pair; alpar@100: ///\e alpar@1064: typedef CMP 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: /// kpeter@606: /// The item-int map must be initialized in such way that it assigns kpeter@606: /// \c PRE_HEAP (-1) to any element to be put in the heap. alpar@100: enum State { kpeter@631: IN_HEAP = 0, ///< = 0. kpeter@631: PRE_HEAP = -1, ///< = -1. kpeter@631: POST_HEAP = -2 ///< = -2. alpar@100: }; alpar@100: alpar@100: private: kpeter@606: std::vector _data; kpeter@606: Compare _comp; kpeter@606: ItemIntMap &_iim; alpar@100: alpar@100: public: alpar@100: /// \brief The constructor. alpar@100: /// alpar@100: /// The constructor. kpeter@606: /// \param map should be given to the constructor, since it is used alpar@100: /// internally to handle the cross references. The value of the map kpeter@606: /// must be \c PRE_HEAP (-1) for every item. kpeter@606: explicit BinHeap(ItemIntMap &map) : _iim(map) {} alpar@209: alpar@100: /// \brief The constructor. alpar@100: /// alpar@100: /// The constructor. kpeter@606: /// \param map 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: /// kpeter@606: /// \param comp The comparator function object. kpeter@606: BinHeap(ItemIntMap &map, const Compare &comp) kpeter@606: : _iim(map), _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. kpeter@606: int size() const { return _data.size(); } alpar@209: 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. kpeter@606: bool empty() const { return _data.empty(); } alpar@100: alpar@100: /// \brief Make empty this heap. alpar@209: /// 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@209: void clear() { kpeter@606: _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 { kpeter@606: 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); kpeter@606: while( hole>0 && less(p,_data[par]) ) { kpeter@606: move(_data[par],hole); alpar@209: hole = par; alpar@209: 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) { kpeter@606: if( less(_data[child-1], _data[child]) ) { alpar@209: --child; alpar@209: } kpeter@606: if( !less(_data[child], p) ) alpar@209: goto ok; kpeter@606: move(_data[child], hole); alpar@209: hole = child; alpar@209: child = second_child(hole); alpar@100: } alpar@100: child--; kpeter@606: if( child 0) { kpeter@606: bubble_down(0, _data[n], n); alpar@100: } kpeter@606: _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) { kpeter@606: int h = _iim[i]; kpeter@606: int n = _data.size()-1; kpeter@606: _iim.set(_data[h].first, POST_HEAP); alpar@100: if( h < n ) { kpeter@606: if ( bubble_up(h, _data[n]) == h) { kpeter@606: bubble_down(h, _data[n], n); alpar@209: } alpar@100: } kpeter@606: _data.pop_back(); alpar@100: } alpar@100: alpar@209: alpar@100: /// \brief Returns the priority of \c i. alpar@100: /// alpar@209: /// This function returns the priority of item \c i. kpeter@606: /// \param i The item. alpar@100: /// \pre \c i must be in the heap. alpar@100: Prio operator[](const Item &i) const { kpeter@606: int idx = _iim[i]; kpeter@606: return _data[idx].second; alpar@100: } alpar@100: alpar@209: /// \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) { kpeter@606: int idx = _iim[i]; alpar@100: if( idx < 0 ) { alpar@209: push(i,p); alpar@100: } kpeter@606: else if( _comp(p, _data[idx].second) ) { alpar@209: bubble_up(idx, Pair(i,p)); alpar@100: } alpar@100: else { kpeter@606: 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. kpeter@606: /// \param i The item. kpeter@606: /// \param p The priority. 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: void decrease(const Item &i, const Prio &p) { kpeter@606: int idx = _iim[i]; alpar@100: bubble_up(idx, Pair(i,p)); alpar@100: } alpar@209: alpar@100: /// \brief Increases the priority of \c i to \c p. alpar@100: /// alpar@209: /// This method sets the priority of item \c i to \c p. kpeter@606: /// \param i The item. kpeter@606: /// \param p The priority. 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: void increase(const Item &i, const Prio &p) { kpeter@606: int idx = _iim[i]; kpeter@606: bubble_down(idx, Pair(i,p), _data.size()); alpar@100: } alpar@100: alpar@209: /// \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 { kpeter@606: int s = _iim[i]; alpar@100: if( s>=0 ) alpar@209: 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@209: /// \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: } kpeter@606: _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) { kpeter@606: int idx = _iim[i]; kpeter@606: _iim.set(i, _iim[j]); kpeter@606: _iim.set(j, idx); kpeter@606: _data[idx].first = j; alpar@100: } alpar@100: alpar@100: }; // class BinHeap alpar@209: alpar@100: } // namespace lemon alpar@100: alpar@100: #endif // LEMON_BIN_HEAP_H