哈希表 基础理论


 

hash 哈希,有的也翻译为散列,哈希表通常基于数组实现,元素存取效率高。

java中常见的hash集合都是使用哈希表来存储元素

  • map:HashMap、LinkedHashMap、Hashtable
  • set:HashSet、LinkedHashSet

 

哈希表中的常见概念

桶 bucket:哈希表中存储元素的位置叫做桶,数组中的一个位置即一个 bucket。

哈希表的容量 capacity:即桶的个数、数组长度。

哈希冲突:又叫做哈希碰撞,多个元素计算得到的哈希地址相同。哈希冲突是否会导致一个bucket中存储多个元素,这要看哈希冲突的解决方式,比如链表法则会在一个bucket中以链表形式存储多个哈希地址相同的元素,开放地址法则不会,会重新寻找新的空桶(哈希地址)。

重哈希 rehashing:也叫作再散列,哈希表存储的元素数量超过阈值时,哈希表自动扩容,重新分配存储位置,将原有元素都复制到新哈希表中。重哈希对性能影响大,应该避免频繁重哈希。

 

哈希函数常见的构建方式(哈希算法)

哈希函数(hash function)的构建原则

  • 便于计算,计算不能太复杂,以减少计算的时间开销。
  • 计算得到的地址分布均匀,即对任一关键字key,f(key) 对应不同地址的概率相等,以尽可能减少冲突。

说明:参与计算的关键字key不是对象本身,而是对象的哈希值 obj.hashCode(),哈希函数 hash(key) 是对哈希值(整数)做计算、处理。
 

1、除留余数法

hash(key) = key % p

p<= 哈希表容量n。优点是可以使计算得到的哈希地址比较均匀、分散,HashMap使用的即除留余数法的变种。

 

2、平方取中法
先求出关键字key的平方值,然后按需取平方值的中间几位作为哈希地址。比如哈希表长度1000,数组下标都是三位数000~999,则取平方值的中间3位。取中的原因:平方后中间几位和关键字中每一位都相关,不同关键字会以较高的概率产生不同的哈希地址。

 

3、分段叠加法
按哈希表地址位数将关键字key分成位数相等的几部分,最后一部分较短的可以舍弃,然后将这些分段对齐相加,舍弃多余的高进位,即得到对应的哈希地址。叠加时可以直接叠加,也可以做一些特殊操作,比如奇数段正序、偶数段倒序。

示例:key=12360324711202065,哈希表长度为1000,数组下标都是三位数 000, 001…999,所以应该把关键字分成3位一段,舍弃最低的两位65

		1   2   3                    1   2   3
		6   0   3                    3   0   6
		2   4   7                    2   4   7
		1   1   2                    2   1   1
	+   0   2   0                +   0   2   0
	————————————————            ——————————————————
    1   1   0   5                	 9   0   7

		 特殊操作                      直接叠加

直接叠加得到 907,正好3位,得到哈希地址 907;特殊操作叠加得到 1105,结果只保留3位,舍弃最高位的1,得到哈希地址 105。

 

4、随机乘数法

hash(key) = n * random(key)

n是哈希表长度,采用随机函数生成一个 0~1 的随机小数,乘以哈希表长度分散到哈希表上,对结果取整得到哈希地址(要使用的数组下标)。

 

5、直接定址法

hash(key) = key + c

在key的基础上与常数进行数学运算。示例:哈希表长度10000,下标范围0~9999,要存储的元素是业务编号,编号范围1~10000,则可以使用 hash(key) = key - 1。

 

解析哈希冲突的常见方式

1、开放地址法
也叫作开放定址法,当关键字key的哈希地址 p=H(key) 出现冲突时,以p为基础生成另一个哈希地址p1,如果p1仍然冲突,再以p为基础生成另一个哈希地址p2…直到找出一个不冲突的哈希地址pi,将元素存入其中。这种方式有一个通用公式

Hi = ( H(key) + di ) % n

n是哈希表的表长(数组长度),di是增量序列,i=1, 2…n。di的取值有3种方式

  • 线性探测再散列:逐渐+1,di = 1 , 2 , 3 , … , n-1
  • 平方探测再散列:也叫作二次探测再散列,二次指的是二次方,di=1^2,-1^2,2^2,-2^2,…,k^2,-k^2 ( k<=n/2 )
  • 随机探测再散列:di 是一组伪随机数列
     

2、拉链法
也叫作链地址法、链表法,将哈希地址相同的元素存储在一个链表中,将链表的头指针直接存储在哈希表(数组)中。
优点:实现简单,且链表中的节点使用的内存空间是动态申请的,避免了内存空间的浪费,十分适合添加元素前不好确定元素个数的情况。HashMap即使用此种方式解决哈希冲突。
 

3、再哈希法
也叫作再散列法,同时构建多个哈希函数,使用第一个哈希函数计算得到的地址存在冲突时,使用第二个哈希函数计算,以此类推,直到计算得到的地址不发生冲突。
缺点:可能需要进行多次哈希计算,增加了计算的时间开销。
 

4、使用公共溢出区
把哈希表(数组)作为基本表,建立一个公共溢出区,把和基本表中冲突的元素都存储在溢出区中。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值