(4)散列函数设计:除留余数法

除留余数法介绍

除留余数法此方法为最常用的构造散列函数方法。对于散列表长为m的散列函数公式为:

f( key ) = key mod p ( p ≤ m )

mod是取模(求余数)的意思。事实上,这方法不仅可以对关键字直接取模,也可在折叠、平方取中后再取模。

一个例子
  • 很显然,本方法的关键就在于选择合适的p, p如果选得不好,就可能会容易产生同义词。下面我们来举个例子看看:

有一个关键字,它有12个记录,现在我们要针对它设计一个散列表。如果采用除留余数法,那么可以先尝试将散列函数设计为f(key) = key mod 12的方法。比如29 mod 12 = 5,所以它存储在下标为5的位置。

不过这也是存在冲突的可能的,因为12 = 2×6 = 3×4。如果关键字中有像18(3×6)、30(5×6)、42(7×6)等数字,它们的余数都为6,这就和78所对应的下标位置冲突了。

  • 甚至极端一些,对于下图的关键字,如果我们让p为12的话,就可能出现下面的情况,所有的关键字都得到了0这个地址数,这未免也太糟糕了点。

但是我们如果不选用p=12来做除留余数法,而选用p=ll,则结果如下:

这个时候就只有12和144有冲突,相对来说,就要好很多了。

如何合理选取p值

使用除留余数法的一个经验是,若散列表表长为m,通常p为小于或等于表长(最好接近m)的最小质数或不包含小于20质因子的合数。

  • 这句话怎么理解呢?要不这样吧,我再举个例子:某散列表的长度为100,散列函数H(k)=k%P,则P通常情况下最好选择哪个呢?A、91 B、93 C、97 D、99
  • 实践证明,当P取小于哈希表长的最大质数时,产生的哈希函数较好。我选97,因为它是离长度值最近的最大 质数
  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
表是一种数据结构,它能够快速地查找和插入数据。表的核心是函数,它将关键字映射到表的位置本题要求设计一个表,使得查找成功时平均查找长度小于2.0,这意味着表需要设计得比较紧凑,冲突的次数要尽量少。 下面是一个可能的解: ```c #include <stdio.h> #include <stdlib.h> #define N 100 #define EMPTY -999 int hash(int key) { return key % N; } int search(int *table, int key) { int pos = hash(key); while (table[pos] != EMPTY && table[pos] != key) { pos = (pos + 1) % N; } if (table[pos] == key) { return pos; } else { return -1; } } void insert(int *table, int key) { int pos = hash(key); while (table[pos] != EMPTY) { pos = (pos + 1) % N; } table[pos] = key; } void init(int *table) { for (int i = 0; i < N; i++) { table[i] = EMPTY; } } int main() { int table[N]; init(table); int count = 0; int sum = 0; for (int i = 0; i < 2 * N; i++) { int key = rand() % (2 * N); int pos = search(table, key); if (pos == -1) { insert(table, key); count++; sum += search(table, key); } if (count == N) { break; } } printf("Average search length: %.2f\n", (float)sum / count); return 0; } ``` 该程序使用除余数计算值,使用线性探测处理冲突。表的大小为100,关键字的取值范围是[0, 199]。表中的空位用-999表示。 在主函数中,程序随机生成两倍大小的关键字集合,并插入到表中。如果表中已经存在该关键字,则不进行插入。当表达到指定大小时,停止插入操作。最后,程序计算平均查找长度并输出结果。 该程序的输出结果可能会有所不同,但一般来说,平均查找长度应该小于2.0。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值