常见基本数据结构——散列

本文深入探讨了散列(哈希)数据结构,包括散列函数的选择、冲突处理策略如分离链接法和开放定址法,以及如何通过调整装填因子优化性能。介绍了线性探测、平方探测、双散列和再散列等解决冲突的方法,强调了装填因子的重要性。此外,还提到了散列在编译器、游戏编程和拼写检查等领域的应用。
摘要由CSDN通过智能技术生成

散列表的实现通常叫做散列。散列是一种用于以常数平均时间执行插入、删除和查找的技术。但是任何排序的信息都不会得到有效的支持。所以FindMax(),FindMin(),以及以线性时间打印的操作都是散列所不支持的。

理想的散列表数据结构值不过是一个包含有关键字的具有固定大小的数组。

关键字映射的函数叫做散列函数,通常散列函数应该运算简单并且保证任何两个不同的关键字映射到不同的单元。不过这是不可能的,因为单元的数目是有限的,然而关键字是用不完的。因此,我们寻找一个散列函数,该函数要在单元之间均匀的分配的关键字。对于两个关键字映射到同一个值的时候,我们称之为冲突,需要设定一个函数来进行处理。

 

散列函数

对于关键字是整数,则一般合理的方法就是直接返回"Key mod TableSize"的结果,除非Key具有某些不理想的性质。例如:表的大小是10,但是关键字的大小都是0为个位。好的大小通常是保证表的大小是一个素数。

通常,关键字是字符串,在这种情况下,散列函数需要仔细的选择。

一种比较简单的方法是把字符串中的字符的ASCLL码值加起来。下面是这种方式的代码实现:

复制代码

Indexx Hash(const char *Key, int TableSize){
    unsigned int HashVal = 0;
    while(*Key != '\0'){
        HashVal += *Key++;    
    } 
    return HashVal % TableSize;
}

复制代码

上述的散列函数实现起来简单而且很快地算出答案。不过,如果表很大的话,函数将不会很好的分配关键字。假设TableSize=10007,并且假设所有的关键字最多有8个字符长,127*8=1016,显然这是不均匀的分配。

 

另一种散列函数有下面的代码所示,假设关键字key至少有两个字符加上NULL结束,729=27^2

假设它们是随机的,而表还是10007的大小,我们就会得到一个合理的均匀分配,虽然3个字符有26^3=17576种可能的组合,但是实际的词汇量却揭示了:3和字母不同的组合数实际上面只有2851种,也只不过有28%的空间被利用上。当表足够大的时候,它们还是不合适的

Index Hash(const char *Key, int TableSize){
    return (Key[0] + 27 * Key[1] + 729 * Key[2]) % TableSize;
}

下面的散列函数,涉及到关键字中的所有字符,并且一般可以分布的很好,程序根据Horner法则计算一个(32的)多项式。

复制代码

Index Hash(const char *Key, int TableSize){
    unsigned int HashVal=0;
    while(*Key != '\0'){
        HashVal = (HashVal<<5) + *Key++;
    }
    return HashVal % TableSize;
}

复制代码

之所以使用32是因为可以使用位运算来加速,并且还可以使用按位异或来代替。上述的散列函数的优点是简单且允许溢出。当关键字长的时候,可以选用部分的关键字。有些程序人员通过只使用奇数位置上的字符来实现他们的散列函数。这

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值