数据结构(十二)散列表
定义
以下简称hahs
应用场景
适合查找与给定值相同的数据,不适合做范围查找,1对多映射查找
问题
冲突,散列表的理论依据是每个不同的关键字通过散列算法得到的结果都是唯一的,而现实中有可能出现几个结果相同的关键字。
hash算法
构造一个散列算法考虑几个方面
直接定址法
按如下公式计算出关键字的hash值,当原始的key不重复,则得到的hash值就不会冲突
数字分析法
抽取关键字的一部分作为hash值
例如手机号,一般可以取后4位或者后4位的变形作为hash值,(公司内部场景)
平方取中法
折叠法
除留余数法
随机数法
java针对stirng的hash算法
hash = 31 * hash + str[i];
其中str[i]表示string的某个位置字符
至于为什么用31那。首先你必须使用一个质数,那又会问,为什么要用质数呢,如果你使用一个有因数的数,那么相乘得到的结果会出现更多的hash冲突。那为什么选择31呢,i*31== (i<<5)-1,可以被编译器优化为移位计算,那为什么不选7呢,i*7==(i<<3)-1,系数尽可能大也可以减少hash冲突,但是太大相乘可能会导致溢出,所以31是一个折中的系数。详细可以参考这个解释
hash冲突解决方法
开放地址法
线性探测法
公式
比如
二次探测法
可以不让关键字都聚集在同一块数据区域汇中(增加离散度)
随机探测法
需要注意的是,这个随机数是一个伪随机数,否则下次找不到hash值了
再hash法
当遇到冲突时,对关键字再进行hash,可以采用不同的hash函数计算,目的是为了得到一个不冲突的hash值
链表法
原理是不处理hash冲突的问题,就是让它冲突,然后把冲突的关键字用链表串联起来,下次找的时候直接遍历链表就行了。多说一句,java的hashmap就是采用这个方法
拿图来说就比如这样
公共溢出区
链表发是在每个位置上建立冲突的集合,而公共溢出区则为建立一个统一的冲突集合,这应该挺好理解。这适用用hash冲突较少的场景,如果多了,会影响性能,要知道遍历链表的复杂度是O(n),还不如直接二分查找了。
新博客地址
http://ixiaosi.art/
欢迎来访 : )