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