Aleph-w  1.5a.2
Biblioteca general de algoritmos y estructuras de datos
 Todo Clases Archivos Funciones Variables 'typedefs' Enumeraciones Amigas Grupos Páginas
tpl_olhash.H
1 
2 # ifndef TPL_OLHASH_H
3 # define TPL_OLHASH_H
4 
5 # include <iostream>
6 # include <primes.H>
7 # include <ahDry.H>
8 # include <hash-dry.H>
9 # include <hash-fct.H>
10 
11 using namespace Primes;
12 
13 using namespace Aleph;
14 
15 # ifdef N
16 # define NBACKUP N
17 # undef N
18 # endif
19 
20 # ifdef M
21 # define MBACKUP M
22 # undef M
23 # endif
24 
25 namespace Aleph {
26 
43  template <typename Key, class Cmp = Aleph::equal_to<Key>>
45 {
46 public:
47 
48  typedef Key Key_Type;
49 
50  typedef Key Item_Type;
51 
53  typedef size_t (*Hash_Fct)(const Key &);
54 
55  enum Status { EMPTY, BUSY, DELETED };
56 
57  struct Bucket
58  {
59  Key key;
60  char status;
61 
62  Bucket() : status(EMPTY) {}
63  void reset() { status = EMPTY; }
64  };
65 
66  static Bucket * key_to_bucket(Key * rec)
67  {
68  Bucket * ret_val = 0;
69  long offset = (long) &ret_val->key;
70  return (Bucket*) ((long) rec - offset);
71  }
72 
73  Bucket * table;
74  size_t N;
75 
76 protected:
77 
78  size_t len;
79  float lower_alpha;
80  float upper_alpha;
81 
82 private:
83 
84  Hash_Fct hash_fct;
85  bool with_resize;
86 
87  bool is_valid_bucket(Bucket * bucket) const
88  {
89  if (bucket < &table[0] or bucket >= &table[len])
90  return false;
91 
92  int offset_with_base = (char*) bucket - (char*) &table[0];
93 
94  return offset_with_base % sizeof(*bucket) == 0;
95  }
96 
97 public:
98 
101  OLhashTable(Hash_Fct __hash_fct = Aleph::dft_hash_fct<Key>,
102  Hash_Fct null_hash_fct = NULL, /* Ficticius compatibily */
103  size_t __len = Primes::DefaultPrime,
104  const float & __lower_alpha = hash_default_lower_alpha,
105  const float & __upper_alpha = hash_default_upper_alpha,
106  const bool __with_resize = true)
107  : table(NULL), N(0), len(Primes::next_prime(__len)),
108  lower_alpha(__lower_alpha), upper_alpha(__upper_alpha),
109  hash_fct(__hash_fct), with_resize(__with_resize)
110  {
111  table = new Bucket [len];
112  }
113 
116  {
117  if (table != NULL)
118  delete [] table;
119  }
120 
121  void swap(OLhashTable & other)
122  {
123  std::swap(table, other.table);
124  std::swap(N, other.N);
125  std::swap(len, other.len);
126  std::swap(hash_fct, other.hash_fct);
127  std::swap(lower_alpha, other.lower_alpha);
128  std::swap(upper_alpha, other.upper_alpha);
129  std::swap(with_resize, other.with_resize);
130  }
131 
132  OLhashTable(const OLhashTable & other)
133  : OLhashTable(other.hash_fct, NULL, other.len,
134  other.lower_alpha, other.upper_alpha, other.with_resize)
135  {
136  copy_from_table(other);
137  }
138 
139  OLhashTable(OLhashTable && other)
140  : OLhashTable(other.hash_fct, NULL, other.len,
141  other.lower_alpha, other.upper_alpha, other.with_resize)
142  {
143  swap(other);
144  }
145 
146  OLhashTable & operator = (const OLhashTable & other)
147  {
148  if (this == &other)
149  return *this;
150 
151  if (len > other.N)
152  clean_table();
153  else
154  {
155  Bucket * new_table = new Bucket [other.len];
156  delete [] table;
157  table = new_table;
158  N = 0;
159  len = other.len;
160  hash_fct = other.hash_fct;
161  lower_alpha = other.lower_alpha;
162  upper_alpha = other.upper_alpha;
163  }
164 
165  copy_from_table(other);
166 
167  return *this;
168  }
169 
170  OLhashTable & operator = (OLhashTable && other)
171  {
172  swap(other);
173  return *this;
174  }
175 
178  Key * search(const Key & key) const
179  {
180  long i = (*hash_fct)(key) % len, c = 0;
181 
182  while (c < len and table[i].status != EMPTY)
183  {
184  if (table[i].status == BUSY and Cmp () (table[i].key, key))
185  return &table[i].key;
186 
187  ++c;
188  if (++i == len)
189  i = 0;
190  }
191 
192  return NULL; // No se encuentra la clave
193  }
194 
195 private:
196 
197  Bucket * allocate_bucket(const Key & key)
198  {
199  if (N >= len)
200  throw std::overflow_error("Hash table is full");
201 
202  size_t i = (*hash_fct)(key) % len;
203 
204  while (table[i].status == BUSY) // find a slot that is not busy
205  {
206  if (Cmp () (key, table[i].key))
207  return NULL;
208 
209  if (++i == len)
210  i = 0;
211  }
212 
213  Bucket * bucket = &table[i];
214 
215  // i contiene celda con DELETED o EMPTY ==> ocuparla
216  bucket->status = BUSY;
217  N++;
218 
219  return bucket;
220  }
221 
227  void deallocate_bucket(Bucket * bucket)
228  {
229  if (not is_valid_bucket(bucket))
230  throw std::invalid_argument("record address is not inside table's range");
231 
232  if (bucket->status != BUSY)
233  throw std::domain_error("Bucket containing record is not busy");
234 
235  --N;
236  int i = bucket - &table[0]; // índice de brecha
237  table[i].status = DELETED;
238  }
239 
240  public:
241 
252  void remove(const Key & key)
253  {
254  Key * key_ptr = search(key);
255  if (key_ptr == NULL)
256  throw std::domain_error("Key not in hash table");
257 
258  remove(key_ptr);
259  }
260 
261  OHASH_COMMON(OLhashTable);
262 
263  Generic_Traverse(Key);
264  Functional_Methods(Key)
265  Equal_To_Method(OLhashTable);
266 
267  Stats stats() const
268  {
269  DynArray<size_t> lens;
270  size_t num_busy = 0, num_deleted = 0, num_empty = 0;
271  size_t max_len = std::numeric_limits<size_t>::min();
272  for (int i = 0; i < len; ++i)
273  switch (table[i].status)
274  {
275  case BUSY:
276  {
277  ++num_busy;
278  const Key & key = table[i].key;
279  long i = (*hash_fct)(key) % len;
280  size_t count = 1;
281 
282  while (true)
283  {
284  if (table[i].status == BUSY and Cmp () (table[i].key, key))
285  break;
286  ++count;
287  if (++i == len)
288  i = 0;
289  }
290 
291  max_len = std::max(max_len, count);
292  update_stat_len(lens, count);
293  break;
294  }
295  case EMPTY:
296  ++num_empty;
297  update_stat_len(lens, 0);
298  break;
299  case DELETED:
300  ++num_deleted;
301  break;
302  }
303 
304  float avg = 0, sum = 0;
305  for (int i = 0; i < lens.size(); ++i)
306  {
307  avg += lens(i)*i;
308  sum += lens(i);
309  }
310 
311  avg /= sum;
312  float var = 0;
313  for (int i = 0; i < lens.size(); ++i)
314  {
315  float s = i - avg;
316  var += lens(i)*s*s;
317  }
318  var /= sum;
319 
320  Stats stats;
321  stats.num_busy = num_busy;
322  stats.num_deleted = num_deleted;
323  stats.num_empty = num_empty;
324  std::swap(lens, stats.lens);
325  stats.avg = avg;
326  stats.var = var;
327  stats.max_len = max_len;
328 
329  return stats;
330  }
331 };
332 
333 }
334 # endif // TPL_OLHASH_H
335 
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Definition: ahAlgo.H:127
Definition: tpl_olhash.H:57
size_t size() const
Retorna dimensión actual (más lejano índice escrito)
Definition: tpl_dynArray.H:523
Itor1 search(Itor1 beg, const Itor1 &end, Itor2 searchBeg, const Itor2 &searchEnd, BinaryPredicate op=BinaryPredicate())
Definition: ahAlgo.H:327
OLhashTable(Hash_Fct __hash_fct=Aleph::dft_hash_fct< Key >, Hash_Fct null_hash_fct=NULL, size_t __len=Primes::DefaultPrime, const float &__lower_alpha=hash_default_lower_alpha, const float &__upper_alpha=hash_default_upper_alpha, const bool __with_resize=true)
Definition: tpl_olhash.H:101
Key * search(const Key &key) const
Definition: tpl_olhash.H:178
~OLhashTable()
Libera toda la memoria ocupada.
Definition: tpl_olhash.H:115
Definition: tpl_dynArray.H:70
Definition: tpl_olhash.H:44

Leandro Rabindranath León