hash简介
- Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
hash冲突
- 对不同的关键字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),这种现象就称为hash冲突
解决hash冲突的方法
一、开放定址法
- 当关键字key的哈希地址 p=f(key) 现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。
- Hi = ( h(key) + di ) Mod m
- 优点:1、记录更容易进行序列化(serialize)操作
2、如果记录总数可以预知,可以创建完美哈希函数,此时处理数据的效率是非常高的 - 缺点:1、存储记录的数目不能超过桶数组的长度,如果超过就需要扩容,而扩容会导致某次操作的时间成本飙升,这在实时或者交互式应用中可能会是一个严重的缺陷
二、拉链法(链地址法)
- 将所有哈希地址为 i 的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第 i 个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
- 优点:1、对于记录总数频繁可变的情况,处理的比较好(也就是避免了动态调整的开销)
2、由于记录存储在结点中,而结点是动态分配,不会造成内存的浪费,所以尤其适合那种记录本身尺寸(size)很大的情况,因为此时指针的开销可以忽略不计了
3、删除记录时,比较方便,直接通过指针操作即可 - 缺点:1、存储的记录是随机分布在内存中的,这样在查询记录时,相比结构紧凑的数据类型(比如数组),哈希表的跳转访问会带来额外的时间开销
三、再hash
- 即构造过个不同的哈希函数,当f1(key) 发生冲突时,使用f2(key)计算,直至不再产生冲突;
- 这种方法不易产生聚集,但增加了计算时间
四、建立公共溢出区
- 将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。