alpar@222: /* FIXME: Copyright ... 
alpar@222:  *
alpar@222:  * This implementation is heavily based on STL's heap functions and
alpar@222:  * the similar class by Alpar Juttner in IKTA...
alpar@222:  */
alpar@222: 
alpar@222: /******
alpar@222:  *
alpar@222:  * BinHeap<KeyType, ValueType, KeyIntMap, [ValueCompare]>
alpar@222:  *
alpar@222:  * Ez az osztaly kulcs-ertek parok tarolasara alkalmas binaris kupacot
alpar@222:  * valosit meg.
alpar@222:  * A kupacban legfolul mindig az a par talalhato, amiben az _ertek_ a
alpar@222:  * legkisebb. (Gondolj a Dijkstra pont-tavolsag kupacara; igazabol ahhoz
alpar@222:  * lett keszitve...)
alpar@222:  *
alpar@222:  * Megjegyzes: egy kicsit gyanus nekem, hogy a kupacos temakorben nem
alpar@222:  * azt hivjak kulcsnak, amit most en annak nevezek. :) En olyan 
alpar@222:  * property_map -os ertelemben hasznalom.
alpar@222:  *
alpar@222:  * A hasznalatahoz szukseg van egy irhato/olvashato property_map-re, ami
alpar@222:  * a kulcsokhoz egy int-et tud tarolni (ezzel tudom megkeresni az illeto
alpar@222:  * elemet a kupacban a csokkentes es hasonlo muveletekhez).
alpar@222:  * A map-re csak referenciat tarol, ugy hogy a kupac elete folyan a map-nek
alpar@222:  * is elnie kell. (???)
alpar@222:  *
alpar@222:  * Ketfele modon hasznalhato:
alpar@222:  * Lusta mod:
alpar@222:  * put(Key, Value) metodussal pakolunk a kupacba,
alpar@222:  * aztan o majd eldonti, hogy ez az elem mar benne van-e es ha igen, akkor
alpar@222:  * csokkentettunk-e rajta, vagy noveltunk.
alpar@222:  * Ehhez nagyon fontos, hogy az atadott property map inicializalva legyen
alpar@222:  * minden szobajovo kulcs ertekre, -1 -es ertekkel!
alpar@222:  * Es ilyen esetben a kulcsokrol lekerdezheto az allapotuk a state metodussal:
alpar@222:  * (nem jart meg a kupacban PRE_HEAP=-1, epp a kupacban van IN_HEAP=0,
alpar@222:  *  mar kikerult a kupacbol POST_HEAP=-2).
alpar@222:  * Szoval ebben a modban a kupac nagyjabol hasznalhato property_map-kent, csak
alpar@222:  * meg meg tudja mondani a "legkisebb" erteku elemet. De csak nagyjabol,
alpar@222:  * hiszen a kupacbol kikerult elemeknek elvesz az ertekuk...
alpar@222:  *
alpar@222:  * Kozvetlen mod:
alpar@222:  * push(Key, Value) metodussal belerakunk a kupacba (ha az illeto kulcs mar
alpar@222:  * benn volt, akkor gaz).
alpar@222:  * increase/decrease(Key k, Value new_value) metodusokkal lehet
alpar@222:  * novelni/csokkenteni az illeto kulcshoz tartozo erteket. (Ha nem volt meg
alpar@222:  * benne a kupacban az illeto kulcs, vagy nem abba az iranyba valtoztattad
alpar@222:  * az erteket, amerre mondtad -- gaz).
alpar@222:  *
alpar@222:  * Termeszetesen a fenti ket modot ertelemszeruen lehet keverni.
alpar@222:  * Ja es mindig nagyon gaz, ha belepiszkalsz a map-be, amit a kupac
alpar@222:  * hasznal. :-))
alpar@222:  *
alpar@222:  *
alpar@222:  * Bocs, most faradt vagyok, majd egyszer leforditom. (Misi)
alpar@222:  *
alpar@222:  */
alpar@222: 
alpar@222: 
alpar@222: #ifndef BIN_HEAP_HH
alpar@222: #define BIN_HEAP_HH
alpar@222: 
alpar@242: ///\file
alpar@242: ///\brief Binary Heap implementation.
alpar@242: 
alpar@222: #include <vector>
alpar@222: #include <utility>
alpar@222: #include <functional>
alpar@222: 
alpar@222: namespace hugo {
alpar@222: 
alpar@224:   /// A Binary Heap implementation.
alpar@222:   template <typename Key, typename Val, typename KeyIntMap,
alpar@222: 	    typename Compare = std::less<Val> >
alpar@222:   class BinHeap {
alpar@222: 
alpar@222:   public:
alpar@222:     typedef Key	             KeyType;
alpar@222:     // FIXME: stl-ben nem ezt hivjak value_type -nak, hanem a kovetkezot...
alpar@222:     typedef Val              ValueType;
alpar@222:     typedef std::pair<KeyType,ValueType>     PairType;
alpar@222:     typedef KeyIntMap        KeyIntMapType;
alpar@222:     typedef Compare          ValueCompare;
alpar@222: 
alpar@222:     /**
alpar@222:      * Each Key element have a state associated to it. It may be "in heap",
alpar@222:      * "pre heap" or "post heap". The later two are indifferent from the
alpar@222:      * heap's point of view, but may be useful to the user.
alpar@222:      *
alpar@222:      * The KeyIntMap _should_ be initialized in such way, that it maps
alpar@222:      * PRE_HEAP (-1) to any element to be put in the heap...
alpar@222:      */
alpar@222:     ///\todo it is used nowhere
alpar@222:     ///
alpar@222:     enum state_enum {
alpar@222:       IN_HEAP = 0,
alpar@222:       PRE_HEAP = -1,
alpar@222:       POST_HEAP = -2
alpar@222:     };
alpar@222: 
alpar@222:   private:
alpar@222:     std::vector<PairType> data;
alpar@222:     Compare comp;
alpar@222:     // FIXME: jo ez igy???
alpar@222:     KeyIntMap &kim;
alpar@222: 
alpar@222:   public:
alpar@222:     BinHeap(KeyIntMap &_kim) : kim(_kim) {}
alpar@222:     BinHeap(KeyIntMap &_kim, const Compare &_comp) : comp(_comp), kim(_kim) {}
alpar@222: 
alpar@222: 
alpar@222:     int size() const { return data.size(); }
alpar@222:     bool empty() const { return data.empty(); }
alpar@222: 
alpar@222:   private:
alpar@222:     static int parent(int i) { return (i-1)/2; }
alpar@222:     static int second_child(int i) { return 2*i+2; }
alpar@222:     bool less(const PairType &p1, const PairType &p2) {
alpar@222:       return comp(p1.second, p2.second);
alpar@222:     }
alpar@222: 
alpar@222:     int bubble_up(int hole, PairType p);
alpar@222:     int bubble_down(int hole, PairType p, int length);
alpar@222: 
alpar@222:     void move(const PairType &p, int i) {
alpar@222:       data[i] = p;
alpar@222:       kim.set(p.first, i);
alpar@222:     }
alpar@222: 
alpar@222:     void rmidx(int h) {
alpar@222:       int n = data.size()-1;
alpar@222:       if( h>=0 && h<=n ) {
alpar@222: 	kim.set(data[h].first, POST_HEAP);
alpar@222: 	if ( h<n ) {
alpar@222: 	  bubble_down(h, data[n], n);
alpar@222: 	}
alpar@222: 	data.pop_back();
alpar@222:       }
alpar@222:     }
alpar@222: 
alpar@222:   public:
alpar@222:     void push(const PairType &p) {
alpar@222:       int n = data.size();
alpar@222:       data.resize(n+1);
alpar@222:       bubble_up(n, p);
alpar@222:     }
alpar@222:     void push(const Key &k, const Val &v) { push(PairType(k,v)); }
alpar@222: 
alpar@222:     Key top() const {
alpar@222:       // FIXME: test size>0 ?
alpar@222:       return data[0].first;
alpar@222:     }
alpar@222:     Val topValue() const {
alpar@222:       // FIXME: test size>0 ?
alpar@222:       return data[0].second;
alpar@222:     }
alpar@222: 
alpar@222:     void pop() {
alpar@222:       rmidx(0);
alpar@222:     }
alpar@222: 
alpar@222:     void erase(const Key &k) {
alpar@222:       rmidx(kim[k]);
alpar@222:     }
alpar@222: 
alpar@222:     Val operator[](const Key &k) const {
alpar@222:       int idx = kim[k];
alpar@222:       return data[idx].second;
alpar@222:     }
alpar@222:     
alpar@222:     void put(const Key &k, const Val &v) {
alpar@222:       int idx = kim[k];
alpar@222:       if( idx < 0 ) {
alpar@222: 	push(k,v);
alpar@222:       }
alpar@222:       else if( comp(v, data[idx].second) ) {
alpar@222: 	bubble_up(idx, PairType(k,v));
alpar@222:       }
alpar@222:       else {
alpar@222: 	bubble_down(idx, PairType(k,v), data.size());
alpar@222:       }
alpar@222:     }
alpar@222: 
alpar@222:     void decrease(const Key &k, const Val &v) {
alpar@222:       int idx = kim[k];
alpar@222:       bubble_up(idx, PairType(k,v));
alpar@222:     }
alpar@222:     void increase(const Key &k, const Val &v) {
alpar@222:       int idx = kim[k];
alpar@222:       bubble_down(idx, PairType(k,v), data.size());
alpar@222:     }
alpar@222: 
alpar@222:     state_enum state(const Key &k) const {
alpar@222:       int s = kim[k];
alpar@222:       if( s>=0 )
alpar@222: 	s=0;
alpar@222:       return state_enum(s);
alpar@222:     }
alpar@222: 
alpar@222:   }; // class BinHeap
alpar@222: 
alpar@222:   
alpar@222:   template <typename K, typename V, typename M, typename C>
alpar@222:   int BinHeap<K,V,M,C>::bubble_up(int hole, PairType p) {
alpar@222:     int par = parent(hole);
alpar@222:     while( hole>0 && less(p,data[par]) ) {
alpar@222:       move(data[par],hole);
alpar@222:       hole = par;
alpar@222:       par = parent(hole);
alpar@222:     }
alpar@222:     move(p, hole);
alpar@222:     return hole;
alpar@222:   }
alpar@222: 
alpar@222:   template <typename K, typename V, typename M, typename C>
alpar@222:   int BinHeap<K,V,M,C>::bubble_down(int hole, PairType p, int length) {
alpar@222:     int child = second_child(hole);
alpar@222:     while(child < length) {
alpar@222:       if( less(data[child-1], data[child]) ) {
alpar@222: 	--child;
alpar@222:       }
alpar@222:       if( !less(data[child], p) )
alpar@222: 	goto ok;
alpar@222:       move(data[child], hole);
alpar@222:       hole = child;
alpar@222:       child = second_child(hole);
alpar@222:     }
alpar@222:     child--;
alpar@222:     if( child<length && less(data[child], p) ) {
alpar@222:       move(data[child], hole);
alpar@222:       hole=child;
alpar@222:     }
alpar@222:   ok:
alpar@222:     move(p, hole);
alpar@222:     return hole;
alpar@222:   }
alpar@222: 
alpar@222: } // namespace hugo
alpar@222: 
alpar@222: #endif // BIN_HEAP_HH