hash总结

散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。散列表(哈希表)是根据关键字直接访问内存存储位置的数据结构,仅支持插入、查找、删除操作。在最坏情况下,查找一个元素的时间为Θ(n),而在一些合理的假设下,查找一个元素的期望时间为O(1)。
散列表是普通数组的推广。对于普通数组:
哈希表的做法其实很简单,就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。在一个普通的数组中,最有效的查找一个元素的方法是直接寻址,时间复杂度是 O(1)。直接寻址的基本思想是:如果存储空间允许,我们可以为每个关键字分配一个位置,每个元素的存储地址就是关键字对应的数组下标。在这种情况下应用直接寻找技术是很有效的。


hash算法:

除法取余法,偶数和偶数相除为偶数,h(k) = k mod m; m记录不要是2的幂或者是10的幂,最好是质数,最好是(散列表表长为m,那么去一个靠近m且小于m的质数),如果散列表的长度和关键字k的取值范围大概确定,那么具体问题具体分析最好。

 

乘法散列法,据说在cpu运算中乘法要比除法效率更快。这需要两步操作:第一,我们将关键字 k 乘以一个常量 A,它的取值范围为 0<A<1,并且提出 kA 的小数部分;接下来,我们将这个值乘以 m,并且取结果的底。乘法散列法的一个优势是对 m 的值没有什么特别的要求。对某个 m,一般指定它的值是 2 的幂。尽管这个方法可以和任何的常量A一起工作,但是它和一些特定的值会工作的更好。最好的选择是依赖于被散列计算的数据的特性。Knuth认为0.618033...是比较理想的值,(即根号5 - 1)/2.


冲突解决:

链地址法,即每一个数组元素存放的是一个链表,发生冲突,那么继续往链表后面add即可。

开放地址法
1,线性探测
2,二次探测
3,双散列

这里只说一下线性探测吧,例如hash函数为 index = key mod m 如果发生冲突的情况下,那么hash函数变为 index = (key+1) mod m


基本原理说了一点,那么看看实际情况吧,以java为例子:

可以说实际应用中hash算法太多了,比如如md5,jedis中用到的mur。。。。


看jdk当中的HashMap

1,hash算法没看明白,总之是各种移位,

http://www.roseindia.net/javatutorials/javahashmap.shtml

2,解决冲突的办法是链地址法


HashMap的其他注意事项:

看她的构造函数:

public HashMap(int initialCapacity,float loadFactor)

第一为初始容量,第二个为负载因子。HashMap(0.75,16)的时候,占16个内存空间,实际上只用到了12个,超过12个就扩容。扩容二倍,即扩容到32个空间如果负载因子是1的话,HashMap(1,16)的时候,占16个内存空间,实际上会填满16个以后才会扩容。还有一点好像大概也应该说一下,HashMap的默认的负载因子是0.75,初始容量是16

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值