数据结构第十一周笔记(2)—— 散列查找 (慕课浙大版本--XiaoYu)

106 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天,点击查看活动详情

11.2 散列函数的构造方法

11.2.1 数字关键词的散列函数构造

一个"好"的散列函数一般应考虑下列两个因素:

  1. 计算简单,以便提高转换速度
  2. 关键词对应的地址空间分布均匀,以尽量减少冲突

数字关键词的散列函数构造

  1. 直接定址法:取关键词的某个线性函数值为散列地址,即h(key) = a×key+b (a、b为常数)image-20220825132959714

  2. 除留余数法(常用)://其实就是把一个大的整数把它转换成一个小的整数,这个小的整数就相当于散列表里面的地址

    1. 散列函数为:h(key) = key mod pimage-20220825133843470
  3. 数字分析法:分析数字关键字在各位上的变化情况,取比较随机的位作为散列地址

    1. 比如:取11位收集号码key的后4位作为地址:散列函数为:h(key)=atoi(key+7) (char*key)image-20220825135138135
    2. int atoi(char*s):将类似"5678"的字符串转换为整数5678
    3. 如果关键词key是18位的身份证号码:image-20220825135313221
    4. image-20220825135441040
  4. 折叠法:把关键词分割成位数相同的几个部分,然后叠加image-20220825140542094

  5. 平方取中法:image-20220825140630018

如果仅改变56793542的最后一位,观察散列值会有什么变化(原散列值为641)。

请计算一下,按照平方取中法,key为56793543的散列值是多少=652

11.2.2 字符串关键词的散列函数构造

字符关键词的散列函数构造

  1. 一个简单的散列函数——ASCII码加和法(ASCII码相加在求个余数)

    1. image-20220826005023076
    2. 假如每个字符的变化范围在0-127,我们把它∑起来,∑后的值在0-1270之间,而变量名实际上的这种变化是非常多的,如果以很窄的计算结果来对付一个很广的这个变量范围就会使得这样的一个哈希函数很容易产生聚集,所以这不是一个很好的办法
  2. 简单的改进——前3个字符移位法

    1. h(key)=(key[0] x 27² + key[1] x 27 + key[2])mod TableSize
    2. 这种方法仍然会产生冲突:string、street、strong、structure等等(前三位是一样的);空间浪费:3000/26³≈30
    3. 空间浪费原因:字符一共有26种变化,所以三个字符的变化一共就26的三次方。而前三位一般出现的情况是3000种,而我们实际上考虑到26³去了,通过上面可以知道浪费的空间足足有30倍
  3. 好的散列函数——移位法

    1. image-20220826101017287
    2. 将数值巨大化,采用32进制相乘image-20220826101121601
    3. 优化方法:(a32+b) =>((a32+b)32+c)=>(((a32+b)32+c) 32+d)
如果直接计算'a'*32^4+'b'*32^3+'c'*32^2+'d'*32+'e'所需要的乘法总次数是4+3+2+1=10次。
​
采用 ((('a'*32+'b')*32+'c')*32+'d')*32+'e'的计算方法,乘法总次数是多少?
​
(顺便思考一下两者时间效率的差别)4
Index Hash(const char*Key,int TableSize)
{
    unsigned int h = 0;//散列函数值,初始化为0
    while(*Key != ‘\0’)//位移映射,这里就是值不为空的意思 
        h = ( h << 5 ) + *Key++;//h << 5是左移五位的意思
    return h % TableSize;//最后求余得到地址
}