[整理] 哈希算法和解决哈希冲突

哈希算法

一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。

这一类查找方法建立在“比较“的基础上,查找的效率依赖于查找过程中所进行的比较次数。 理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。

哈希函数有6种实现方式:

A. 直接定址法

取关键字的线性函数值作为哈希地址。
例如:有一个从1到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字自身。

B. 数字分析法

取关键字的中的若干位作为哈希地址。
例如:有学生的生日数据如下:
年.月.日
75.10.03
75.11.23
76.03.02
经分析,第一位,第二位,第三位重复的可能性大,取这三位造成冲突的机会增加,所以尽量不取前三位,取后三位比较好。

C. 平方取中法

取关键字平方后的中间几位作为哈希地址。

D. 折叠法

将关键字分割成位数相同的几部分(最后一部分可以不同),然后取这几部分的叠加和作为哈希地址。
例如:每一种西文图书都有一个国际标准图书编号,它是一个10位的十进制数字,若要以它作关键字建立一个哈希表,当馆藏书种类不到10,000时,可采用此法构造一个四位数的哈希函数。

E. 除留余数法

取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。
H(key) = key MOD p ,p<=m ,m为不大于哈希表的数。

F. 随机函数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即
H(key)=random(key),其中random为随机函数。通常用于关键字长度不等时采用此法。

上述五中实现方式中最常用的是除留余数法。

哈希冲突

通过哈希函数寻址的过程可能出现“冲突”:即若干个不同的key却对应相同的哈希地址。

A. 拉链法(链地址法)

将所有哈希地址相同的元素i构成一个单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在单链表中进行。链地址法适用于经常进行插入和删除的情况。

注:Java的hashmap是此法

B. 多哈希法

设计二种甚至多种哈希函数,可以避免冲突,但是冲突几率还是有的,函数设计的越好或越多都可以将几率降到最低(除非人品太差,否则几乎不可能冲突)。

C. 开放地址法

当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi。
公式:Hi=(H(key)+di) MOD m i=1,2,...,k(k<=m-1)
其中,m为哈希表的表长。di 是产生冲突的时候的增量序列。

  • 如果di值可能为1,2,3,...m-1,称线性探测再散列。
  • 如果di取1,则每次冲突之后,向后移动1个位置.如果di取值可能为1,-1,4,-4,9,-9,16,-16,...kk,-kk(k<=m/2)称二次探测再散列。
  • 如果di取值可能为伪随机数列。称伪随机探测再散列。

D. 建域法(建立公共溢出区)

这种方法就是将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
假设哈希函数的值域为[0,m-1],则设向量HashTable[0..m-1]为基本表,另外设立存储空间向量OverTable[0..v]用以存储发生冲突的记录。

posted @ 2020-11-25 22:01  哆啦梦乐园  阅读(306)  评论(0编辑  收藏  举报