@@ -46,6 +46,19 @@ int main() {
46
46
*/
47
47
48
48
/*
49
+ 2013-05-02 (0.2.8):
50
+
51
+ * Use quadratic probing. When the capacity is power of 2, stepping function
52
+ i*(i+1)/2 guarantees to traverse each bucket. It is better than double
53
+ hashing on cache performance and is more robust than linear probing.
54
+
55
+ In theory, double hashing should be more robust than quadratic probing.
56
+ However, my implementation is probably not for large hash tables, because
57
+ the second hash function is closely tied to the first hash function,
58
+ which reduce the effectiveness of double hashing.
59
+
60
+ Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
61
+
49
62
2011-12-29 (0.2.7):
50
63
51
64
* Minor code clean up; no actual effect.
@@ -110,7 +123,7 @@ int main() {
110
123
Generic hash table library.
111
124
*/
112
125
113
- #define AC_VERSION_KHASH_H "0.2.6 "
126
+ #define AC_VERSION_KHASH_H "0.2.8 "
114
127
115
128
#include <stdlib.h>
116
129
#include <string.h>
@@ -147,12 +160,6 @@ typedef khint_t khiter_t;
147
160
#define __ac_set_isboth_false (flag , i ) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
148
161
#define __ac_set_isdel_true (flag , i ) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
149
162
150
- #ifdef KHASH_LINEAR
151
- #define __ac_inc (k , m ) 1
152
- #else
153
- #define __ac_inc (k , m ) (((k)>>3 ^ (k)<<3) | 1) & (m)
154
- #endif
155
-
156
163
#define __ac_fsize (m ) ((m) < 16? 1 : (m)>>4)
157
164
158
165
#ifndef kroundup32
@@ -213,12 +220,12 @@ static const double __ac_HASH_UPPER = 0.77;
213
220
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
214
221
{ \
215
222
if (h->n_buckets) { \
216
- khint_t inc, k, i, last, mask; \
223
+ khint_t k, i, last, mask, step = 0; \
217
224
mask = h->n_buckets - 1; \
218
225
k = __hash_func(key); i = k & mask; \
219
- inc = __ac_inc(k, mask); last = i; /* inc==1 for linear probing */ \
226
+ last = i; \
220
227
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
221
- i = (i + inc ) & mask ; \
228
+ i = (i + (++step)) & mask; \
222
229
if (i == last) return h->n_buckets; \
223
230
} \
224
231
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
@@ -258,11 +265,10 @@ static const double __ac_HASH_UPPER = 0.77;
258
265
if (kh_is_map ) val = h -> vals [j ]; \
259
266
__ac_set_isdel_true (h -> flags , j ); \
260
267
while (1 ) { /* kick-out process; sort of like in Cuckoo hashing */ \
261
- khint_t inc , k , i ; \
268
+ khint_t k , i , step = 0 ; \
262
269
k = __hash_func (key ); \
263
270
i = k & new_mask ; \
264
- inc = __ac_inc (k , new_mask ); \
265
- while (!__ac_isempty (new_flags , i )) i = (i + inc ) & new_mask ; \
271
+ while (!__ac_isempty (new_flags , i )) i = (i + (++ step )) & new_mask ; \
266
272
__ac_set_isempty_false (new_flags , i ); \
267
273
if (i < h -> n_buckets && __ac_iseither (h -> flags , i ) == 0 ) { /* kick out the existing element */ \
268
274
{ khkey_t tmp = h -> keys [i ]; h -> keys [i ] = key ; key = tmp ; } \
@@ -301,14 +307,14 @@ static const double __ac_HASH_UPPER = 0.77;
301
307
} \
302
308
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
303
309
{ \
304
- khint_t inc , k , i , site , last , mask = h -> n_buckets - 1 ; \
310
+ khint_t k , i , site , last , mask = h -> n_buckets - 1 , step = 0 ; \
305
311
x = site = h -> n_buckets ; k = __hash_func (key ); i = k & mask ; \
306
312
if (__ac_isempty (h -> flags , i )) x = i ; /* for speed up */ \
307
313
else { \
308
- inc = __ac_inc ( k , mask ); last = i ; \
314
+ last = i ; \
309
315
while (!__ac_isempty (h -> flags , i ) && (__ac_isdel (h -> flags , i ) || !__hash_equal (h -> keys [i ], key ))) { \
310
316
if (__ac_isdel (h -> flags , i )) site = i ; \
311
- i = (i + inc ) & mask ; \
317
+ i = (i + ( ++ step )) & mask ; \
312
318
if (i == last ) { x = site ; break ; } \
313
319
} \
314
320
if (x == h -> n_buckets ) { \
0 commit comments