我正在用玩具语言试验一些数据结构,因为我做了大量的文本处理,所以我希望字符串操作能够快速完成。我将字符串存储为具有缓存长度和哈希值的不可变绳索。目标是仅在实例化绳索的叶子节点时执行散列函数。是否有任何现有的哈希函数可以做到这一点?
我的绳索结构如下:
#define HASHLEN 128
#define HASHMUL 2
typedef unsigned long hashtype;
typedef struct rope rope;
// K&R2 hash function
hashtype hash(const char *s) {
hashtype h = 0;
while (*s != '\0') {
h = h * HASHMUL + *s++;
}
return h; // won't be modded until the actual table access is performed
}
struct rope {
unsigned weight;
hashtype hash;
rope *left; // if NULL, indicates that r->right is a char *
void *right; // if r->left is non-NULL, r->right is a rope *
};
和连接函数如下所示:
// integer exponentiation--by squaring
hashtype iexp(hashtype k, unsigned n);
rope *newrope(const char *s) {
rope *r = (rope *) malloc(sizeof(rope));
r->weight = strlen(s);
r->hash = hash(s);
r->left = NULL;
r->right = (void *) s;
return r;
}
rope *ropecat(rope *left, rope *right) {
rope *r = (rope *) malloc(sizeof(rope));
r->weight = left->weight + right->weight;
r->hash = left->hash * iexp(HASHMUL, right->weight) + right->hash;
r->left = left;
r->right = (void *) right;
return r;
}
较大的素数对于HASHMUL
会更好(K& R2使用31,我听说33是“最好的”),但是我担心哈希函数的快速增长长字符串,它可能会绕过ULONG_MAX
并打破哈希机制,所以我选择了一个可能更顺畅地包裹的数字。同时将HASHMUL
设置为2可以将left->hash * iexp(HASHMUL->hash, right->weight)
重写为left->hash << right->weight
,将HASHLEN
设置为128或其他二进制数可让我使用r->hash & (HASHLEN-1)
代替{{1} }}
这就是我要做的事情的概要。我正在寻找一种快速,在恒定时间内分配的散列函数,并且具有合理的分布。天真的K&amp; R2散列函数在这里是否正常工作,或者我应该使用不同的r->hash % HASHLEN
,还是应该完全寻找另一个散列函数?