src/work/jacint/bin_heap.hh
author alpar
Sat, 20 Mar 2004 16:13:19 +0000
changeset 217 fc549fac0dd0
parent 170 9091b1ebca27
permissions -rw-r--r--
Several bugfixes
jacint@170
     1
/* FIXME: Copyright ... 
jacint@170
     2
 *
jacint@170
     3
 * This implementation is heavily based on STL's heap functions and
jacint@170
     4
 * the similar class by Alpar Juttner in IKTA...
jacint@170
     5
 */
jacint@170
     6
jacint@170
     7
/******
jacint@170
     8
 *
jacint@170
     9
 * BinHeap<KeyType, ValueType, KeyIntMap, [ValueCompare]>
jacint@170
    10
 *
jacint@170
    11
 * Ez az osztaly kulcs-ertek parok tarolasara alkalmas binaris kupacot
jacint@170
    12
 * valosit meg.
jacint@170
    13
 * A kupacban legfolul mindig az a par talalhato, amiben az _ertek_ a
jacint@170
    14
 * legkisebb. (Gondolj a Dijkstra pont-tavolsag kupacara; igazabol ahhoz
jacint@170
    15
 * lett keszitve...)
jacint@170
    16
 *
jacint@170
    17
 * Megjegyzes: egy kicsit gyanus nekem, hogy a kupacos temakorben nem
jacint@170
    18
 * azt hivjak kulcsnak, amit most en annak nevezek. :) En olyan 
jacint@170
    19
 * property_map -os ertelemben hasznalom.
jacint@170
    20
 *
jacint@170
    21
 * A hasznalatahoz szukseg van egy irhato/olvashato property_map-re, ami
jacint@170
    22
 * a kulcsokhoz egy int-et tud tarolni (ezzel tudom megkeresni az illeto
jacint@170
    23
 * elemet a kupacban a csokkentes es hasonlo muveletekhez).
jacint@170
    24
 * A map-re csak referenciat tarol, ugy hogy a kupac elete folyan a map-nek
jacint@170
    25
 * is elnie kell. (???)
jacint@170
    26
 *
jacint@170
    27
 * Ketfele modon hasznalhato:
jacint@170
    28
 * Lusta mod:
jacint@170
    29
 * put(Key, Value) metodussal pakolunk a kupacba,
jacint@170
    30
 * aztan o majd eldonti, hogy ez az elem mar benne van-e es ha igen, akkor
jacint@170
    31
 * csokkentettunk-e rajta, vagy noveltunk.
jacint@170
    32
 * Ehhez nagyon fontos, hogy az atadott property map inicializalva legyen
jacint@170
    33
 * minden szobajovo kulcs ertekre, -1 -es ertekkel!
jacint@170
    34
 * Es ilyen esetben a kulcsokrol lekerdezheto az allapotuk a state metodussal:
jacint@170
    35
 * (nem jart meg a kupacban PRE_HEAP=-1, epp a kupacban van IN_HEAP=0,
jacint@170
    36
 *  mar kikerult a kupacbol POST_HEAP=-2).
jacint@170
    37
 * Szoval ebben a modban a kupac nagyjabol hasznalhato property_map-kent, csak
jacint@170
    38
 * meg meg tudja mondani a "legkisebb" erteku elemet. De csak nagyjabol,
jacint@170
    39
 * hiszen a kupacbol kikerult elemeknek elvesz az ertekuk...
jacint@170
    40
 *
jacint@170
    41
 * Kozvetlen mod:
jacint@170
    42
 * push(Key, Value) metodussal belerakunk a kupacba (ha az illeto kulcs mar
jacint@170
    43
 * benn volt, akkor gaz).
jacint@170
    44
 * increase/decrease(Key k, Value new_value) metodusokkal lehet
jacint@170
    45
 * novelni/csokkenteni az illeto kulcshoz tartozo erteket. (Ha nem volt meg
jacint@170
    46
 * benne a kupacban az illeto kulcs, vagy nem abba az iranyba valtoztattad
jacint@170
    47
 * az erteket, amerre mondtad -- gaz).
jacint@170
    48
 *
jacint@170
    49
 * Termeszetesen a fenti ket modot ertelemszeruen lehet keverni.
jacint@170
    50
 * Ja es mindig nagyon gaz, ha belepiszkalsz a map-be, amit a kupac
jacint@170
    51
 * hasznal. :-))
jacint@170
    52
 *
jacint@170
    53
 *
jacint@170
    54
 * Bocs, most faradt vagyok, majd egyszer leforditom. (Misi)
jacint@170
    55
 *
jacint@170
    56
 */
jacint@170
    57
jacint@170
    58
jacint@170
    59
#ifndef BIN_HEAP_HH
jacint@170
    60
#define BIN_HEAP_HH
jacint@170
    61
jacint@170
    62
#include <vector>
jacint@170
    63
#include <utility>
jacint@170
    64
#include <functional>
jacint@170
    65
jacint@170
    66
namespace hugo {
jacint@170
    67
jacint@170
    68
  template <typename Key, typename Val, typename KeyIntMap,
jacint@170
    69
	    typename Compare = std::less<Val> >
jacint@170
    70
  class BinHeap {
jacint@170
    71
jacint@170
    72
  public:
jacint@170
    73
    typedef Key	             KeyType;
jacint@170
    74
    // FIXME: stl-ben nem ezt hivjak value_type -nak, hanem a kovetkezot...
jacint@170
    75
    typedef Val              ValueType;
jacint@170
    76
    typedef std::pair<KeyType,ValueType>     PairType;
jacint@170
    77
    typedef KeyIntMap        KeyIntMapType;
jacint@170
    78
    typedef Compare          ValueCompare;
jacint@170
    79
jacint@170
    80
    /**
jacint@170
    81
     * Each Key element have a state associated to it. It may be "in heap",
jacint@170
    82
     * "pre heap" or "post heap". The later two are indifferent from the
jacint@170
    83
     * heap's point of view, but may be useful to the user.
jacint@170
    84
     *
jacint@170
    85
     * The KeyIntMap _should_ be initialized in such way, that it maps
jacint@170
    86
     * PRE_HEAP (-1) to any element to be put in the heap...
jacint@170
    87
     */
jacint@170
    88
    enum state_enum {
jacint@170
    89
      IN_HEAP = 0,
jacint@170
    90
      PRE_HEAP = -1,
jacint@170
    91
      POST_HEAP = -2
jacint@170
    92
    };
jacint@170
    93
jacint@170
    94
  private:
jacint@170
    95
    std::vector<PairType> data;
jacint@170
    96
    Compare comp;
jacint@170
    97
    // FIXME: jo ez igy???
jacint@170
    98
    KeyIntMap &kim;
jacint@170
    99
jacint@170
   100
  public:
jacint@170
   101
    BinHeap(KeyIntMap &_kim) : kim(_kim) {}
jacint@170
   102
    BinHeap(KeyIntMap &_kim, const Compare &_comp) : comp(_comp), kim(_kim) {}
jacint@170
   103
jacint@170
   104
jacint@170
   105
    int size() const { return data.size(); }
jacint@170
   106
    bool empty() const { return data.empty(); }
jacint@170
   107
jacint@170
   108
  private:
jacint@170
   109
    static int parent(int i) { return (i-1)/2; }
jacint@170
   110
    static int second_child(int i) { return 2*i+2; }
jacint@170
   111
    bool less(const PairType &p1, const PairType &p2) {
jacint@170
   112
      return comp(p1.second, p2.second);
jacint@170
   113
    }
jacint@170
   114
jacint@170
   115
    int bubble_up(int hole, PairType p);
jacint@170
   116
    int bubble_down(int hole, PairType p, int length);
jacint@170
   117
jacint@170
   118
    void move(const PairType &p, int i) {
jacint@170
   119
      data[i] = p;
jacint@170
   120
      kim.set(p.first, i);
jacint@170
   121
    }
jacint@170
   122
jacint@170
   123
    void rmidx(int h) {
jacint@170
   124
      int n = data.size()-1;
jacint@170
   125
      if( h>=0 && h<=n ) {
jacint@170
   126
	kim.set(data[h].first, POST_HEAP);
jacint@170
   127
	if ( h<n ) {
jacint@170
   128
	  bubble_down(h, data[n], n);
jacint@170
   129
	}
jacint@170
   130
	data.pop_back();
jacint@170
   131
      }
jacint@170
   132
    }
jacint@170
   133
jacint@170
   134
  public:
jacint@170
   135
    void push(const PairType &p) {
jacint@170
   136
      int n = data.size();
jacint@170
   137
      data.resize(n+1);
jacint@170
   138
      bubble_up(n, p);
jacint@170
   139
    }
jacint@170
   140
    void push(const Key &k, const Val &v) { push(PairType(k,v)); }
jacint@170
   141
jacint@170
   142
    Key top() const {
jacint@170
   143
      // FIXME: test size>0 ?
jacint@170
   144
      return data[0].first;
jacint@170
   145
    }
jacint@170
   146
    Val topValue() const {
jacint@170
   147
      // FIXME: test size>0 ?
jacint@170
   148
      return data[0].second;
jacint@170
   149
    }
jacint@170
   150
jacint@170
   151
    void pop() {
jacint@170
   152
      rmidx(0);
jacint@170
   153
    }
jacint@170
   154
jacint@170
   155
    void erase(const Key &k) {
alpar@217
   156
      rmidx(kim[k]);
jacint@170
   157
    }
jacint@170
   158
alpar@217
   159
    Val operator[](const Key &k) const {
alpar@217
   160
      int idx = kim[k];
jacint@170
   161
      return data[idx].second;
jacint@170
   162
    }
alpar@217
   163
    
jacint@170
   164
    void put(const Key &k, const Val &v) {
alpar@217
   165
      int idx = kim[k];
jacint@170
   166
      if( idx < 0 ) {
jacint@170
   167
	push(k,v);
jacint@170
   168
      }
jacint@170
   169
      else if( comp(v, data[idx].second) ) {
jacint@170
   170
	bubble_up(idx, PairType(k,v));
jacint@170
   171
      }
jacint@170
   172
      else {
jacint@170
   173
	bubble_down(idx, PairType(k,v), data.size());
jacint@170
   174
      }
jacint@170
   175
    }
jacint@170
   176
jacint@170
   177
    void decrease(const Key &k, const Val &v) {
alpar@217
   178
      int idx = kim[k];
jacint@170
   179
      bubble_up(idx, PairType(k,v));
jacint@170
   180
    }
jacint@170
   181
    void increase(const Key &k, const Val &v) {
alpar@217
   182
      int idx = kim[k];
jacint@170
   183
      bubble_down(idx, PairType(k,v), data.size());
jacint@170
   184
    }
jacint@170
   185
jacint@170
   186
    state_enum state(const Key &k) const {
alpar@217
   187
      int s = kim[k];
jacint@170
   188
      if( s>=0 )
jacint@170
   189
	s=0;
jacint@170
   190
      return state_enum(s);
jacint@170
   191
    }
jacint@170
   192
jacint@170
   193
  }; // class BinHeap
jacint@170
   194
jacint@170
   195
  
jacint@170
   196
  template <typename K, typename V, typename M, typename C>
jacint@170
   197
  int BinHeap<K,V,M,C>::bubble_up(int hole, PairType p) {
jacint@170
   198
    int par = parent(hole);
jacint@170
   199
    while( hole>0 && less(p,data[par]) ) {
jacint@170
   200
      move(data[par],hole);
jacint@170
   201
      hole = par;
jacint@170
   202
      par = parent(hole);
jacint@170
   203
    }
jacint@170
   204
    move(p, hole);
jacint@170
   205
    return hole;
jacint@170
   206
  }
jacint@170
   207
jacint@170
   208
  template <typename K, typename V, typename M, typename C>
jacint@170
   209
  int BinHeap<K,V,M,C>::bubble_down(int hole, PairType p, int length) {
jacint@170
   210
    int child = second_child(hole);
jacint@170
   211
    while(child < length) {
jacint@170
   212
      if( less(data[child-1], data[child]) ) {
jacint@170
   213
	--child;
jacint@170
   214
      }
jacint@170
   215
      if( !less(data[child], p) )
jacint@170
   216
	goto ok;
jacint@170
   217
      move(data[child], hole);
jacint@170
   218
      hole = child;
jacint@170
   219
      child = second_child(hole);
jacint@170
   220
    }
jacint@170
   221
    child--;
jacint@170
   222
    if( child<length && less(data[child], p) ) {
jacint@170
   223
      move(data[child], hole);
jacint@170
   224
      hole=child;
jacint@170
   225
    }
jacint@170
   226
  ok:
jacint@170
   227
    move(p, hole);
jacint@170
   228
    return hole;
jacint@170
   229
  }
jacint@170
   230
jacint@170
   231
} // namespace hugo
jacint@170
   232
jacint@170
   233
#endif // BIN_HEAP_HH