Skip to content

Commit 0afbad1

Browse files
committed
khash-0.2.8: use quadratic probing
1 parent c944fdf commit 0afbad1

File tree

1 file changed

+22
-16
lines changed

1 file changed

+22
-16
lines changed

khash.h

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ int main() {
4646
*/
4747

4848
/*
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+
4962
2011-12-29 (0.2.7):
5063
5164
* Minor code clean up; no actual effect.
@@ -110,7 +123,7 @@ int main() {
110123
Generic hash table library.
111124
*/
112125

113-
#define AC_VERSION_KHASH_H "0.2.6"
126+
#define AC_VERSION_KHASH_H "0.2.8"
114127

115128
#include <stdlib.h>
116129
#include <string.h>
@@ -147,12 +160,6 @@ typedef khint_t khiter_t;
147160
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
148161
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
149162

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-
156163
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
157164

158165
#ifndef kroundup32
@@ -213,12 +220,12 @@ static const double __ac_HASH_UPPER = 0.77;
213220
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
214221
{ \
215222
if (h->n_buckets) { \
216-
khint_t inc, k, i, last, mask; \
223+
khint_t k, i, last, mask, step = 0; \
217224
mask = h->n_buckets - 1; \
218225
k = __hash_func(key); i = k & mask; \
219-
inc = __ac_inc(k, mask); last = i; /* inc==1 for linear probing */ \
226+
last = i; \
220227
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; \
222229
if (i == last) return h->n_buckets; \
223230
} \
224231
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
@@ -258,11 +265,10 @@ static const double __ac_HASH_UPPER = 0.77;
258265
if (kh_is_map) val = h->vals[j]; \
259266
__ac_set_isdel_true(h->flags, j); \
260267
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
261-
khint_t inc, k, i; \
268+
khint_t k, i, step = 0; \
262269
k = __hash_func(key); \
263270
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; \
266272
__ac_set_isempty_false(new_flags, i); \
267273
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
268274
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
@@ -301,14 +307,14 @@ static const double __ac_HASH_UPPER = 0.77;
301307
} \
302308
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
303309
{ \
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; \
305311
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
306312
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
307313
else { \
308-
inc = __ac_inc(k, mask); last = i; \
314+
last = i; \
309315
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
310316
if (__ac_isdel(h->flags, i)) site = i; \
311-
i = (i + inc) & mask; \
317+
i = (i + (++step)) & mask; \
312318
if (i == last) { x = site; break; } \
313319
} \
314320
if (x == h->n_buckets) { \

0 commit comments

Comments
 (0)