与红黑树或者二叉平衡树相比这些树之类的数据结构都是从根节点开始寻找我们需要的值,而哈希表则是通过一种特殊的函数查找关键字key直接确定我们想要的寻找的值的具体位置也就是相对应的地址,不需要一个个得去比较从而提高效率。
index=H(key)(H代表得是哈希函数)
构造:
通常来说一共有五种方法来构造哈希表:
- 直接定址法
- 数字分析法
- 平方取中法
- 折叠法
- 除留余数法
其中通常使用除留取余法,在这里只介绍除留取余法:
H(key)=key MOD p (p<=m m为表长)
很明显,如何选取p是个关键问题。
使用举例
比如我们存储3 6 9,那么p就不能取3
因为 3 MOD 3 == 6 MOD 3 == 9 MOD 3
p应为不大于m的质数或是不含20以下的质因子的合数,这样可以减少地址的重复(冲突)
比如key = 7,39,18,24,33,21时取表长m为9 p为7 那么存储如下
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
key | 7 | 21(冲突后移) | 24 | 39 | 18(冲突后移) | 33(冲突后移) |
设计一个哈希函数需要考虑以下几个因素:
1.计算散列地址所需要的时间(即hash函数本身不要太复杂)
2.关键字的长度
3.表长
4.关键字分布是否均匀,是否有规律可循
5.设计的hash函数在满足以上条件的情况下尽量减少冲突
可以观察到进行构造哈希表的时候会不可避免地发生计算出得地址重复得情况,称为哈希冲突。
解决方法:
- 开放定址法
- 链地址法
- 公共溢出区法
建立一个特殊存储空间,专门存放冲突的数据。此种方法适用于数据和冲突较少的情况。 - 再散列法
准备若干个hash函数,如果使用第一个hash函数发生了冲突,就使用第二个hash函数,第二个也冲突,使用第三个……
重点了解一下开放定制法和链地址法
开放定址法
链地址法:
产生hash冲突后在存储数据后面加一个指针,指向后面冲突的数据
(使用随机探测再散列的例子中)
查找:
查找过程和造表过程一致,假设采用开放定址法处理冲突,则查找过程为:
对于给定的key,计算hash地址index = H(key)
如果数组arr【index】的值为空 则查找不成功
如果数组arr【index】== key 则查找成功
否则 使用冲突解决方法求下一个地址,直到arr【index】== key或者 arr【index】==null
删除:
首先链地址法是可以直接删除元素的,但是开放定址法是不行的,拿前面的双探测再散列来说,假如我们删除了元素1,将其位置置空,那 23就永远找不到了。正确做法应该是删除之后置入一个原来不存在的数据,比如-1