Hash表原理详解

Hash(散列)表

一、优势:
Hash函数可以通过key直接查找并确定值所在位置,而不需要像二叉树那样从根节点开始逐个比较排查。

二、Hash函数构造方法:

1、直接定制法——仅适用于地址大小=关键字的情况
该方法构造的Hash函数为线性函数, H(key)=a*key+b。
例如统计某地区某年龄的人数:
在这里插入图片描述
需要查找哪个年龄的人数,就直接找对应的就行。这种哈希函数构造简单,且不会产生哈希冲突(后文会讲),但限制较大。

2、除留余数法——最常用
H(key)=key MOD p (p<=m m为表长)说白了就是除以一个数p得到余数,用余数来作为哈希地址。
那么余数该如何选择呢?
理论研究表明,除留余数法的模p应取不大于表长且最接近表长m素数或是不含20以下的质因子的合数,且p最好取1.1n~1.7n之间的一个素数(n为存在的数据元素个数)。例如:当n=7时,p最好取11、13等素数
举个例子:
有7、22、18、30、39、24等几个数,表长为9,取p=7,则7MOD7=0,7就放在0的位置上;22MOD7=1,22就放在1的位置上;以此类推,有冲突就先后移。

3、数字分析法——数字位数大、且有规律可循(事先知道数据分布)
举个例子——同村同年龄人员的身份证号。同村同年的话,他们的身份证的前面数位都是相同的,就可以用后面不同的来存储。
例如:H(key)=key%100000

4、平方取中位数法——数据位数小(事先不知道数据分布)
将数据平方(平方的目的是为了扩大差异),再取中位数作为哈希地址。
例如:key=1356 平方得到1838736,可取387作为地址;
key=2431 平方得到5909761,可取097作为地址。

5、折叠法——数字位数大(事先不知道数据分布)
例如:key=123 456 789,可以存储在6 15 24 取其后三位524作为hash地址。

三、Hash冲突解决方法:

1、开放定址法(再散列法):
基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:
Hi=(H(key)+di)% m i=1,2,…,n
其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。
主要有以下三种:

a、线性探测再散列:
dii=1,2,3,…,m-1
其特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

b、二次探测再散列
di=12,-12,22,-22,…,k2,-k2 ( k<=m/2 )
其特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

c、伪随机探测再散列
di=伪随机数序列。
具体实现时应建立一个伪随机数发生器,eg.(i=(i+p)%m),并给出一个随机数作为起点。
例子:(引自 http://blog.csdn.net/tanggao1314/article/details/51457585)
已知哈希表长度m=11,哈希函数为:H(key)= key % 11,则H(47)=3,H(26)=4,H(60)=5,假设下一个关键字为69,则H(69)=3,与47冲突。
1.
线性探测再散列处理冲突,下一个哈希地址为H1=(3 + 1)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 + 2)% 11 = 5,还是冲突,继续找下一个哈希地址为H3=(3 + 3)% 11 = 6,此时不再冲突,将69填入5号单元。
2.
二次探测再散列处理冲突,下一个哈希地址为H1=(3 + 12)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 - 12)% 11 = 2,此时不再冲突,将69填入2号单元)。
3.
伪随机探测再散列处理冲突,且伪随机数序列为:2,5,9,………,则下一个哈希地址为H1=(3 + 2)% 11 = 5,仍然冲突,再找下一个哈希地址为H2=(3 + 5)% 11 = 8,此时不再冲突,将69填入8号单元。

2、再哈希法——同时构造多个不同的哈希函数:
Hi=RH1(key) i=1,2,…,k
当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

3、链地址法:
基本思想:将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

4、建立溢出表:
基本思想:将Hash表分为基本表和溢出表两部分,在基本表中发生冲突的元素都放入溢出表中。

四、Hash表的查找
1、查找过程和造表过程一致,假设采用开放定址法处理冲突,则查找过程为:
对于给定的key,计算hash地址index = H(key)
如果数组arr【index】的值为空 则查找不成功;
如果数组arr【index】== key 则查找成功;
否则,使用冲突解决方法求下一个地址,直到arr【index】== key或者 arr【index】==null。

2、查找效率限制——ASL(平均查找长度)
其影响因素有:
选用的hash函数;
选用的处理冲突的方法;
hash表的饱和度,即装载因子 α=n/m(n表示实际装载数据长度 m为表长)。
一般情况,假设hash函数是均匀的,则在讨论ASL时可以不考虑其它的因素,hash表的ASL是处理冲突方法和装载因子的函数。
前人已经证明,查找成功时如下结果:
在这里插入图片描述
可以看到无论哪个函数,装载因子越大,平均查找长度越大,那么装载因子α越小越好?也不是,就像100的表长只存一个数据,α是小了,但是空间利用率不高啊,这里就是时间空间的取舍问题了。通常情况下,认为α=0.75是时间空间综合利用效率最高的情况。
上面的这个表可是特别有用的。假设我现在有10个数据,想使用链地址法解决冲突,并要求平均查找长度<2
那么有1+α/2 <2
α<2
即 n/m<2 (n=10)
m>10/2
m>5 即采用链地址法,使得平均查找长度< 2 那么m>5
各种树的平均查找长度,是基于存储数据n的函数,但hash表不同,他是基于装载因子的函数,也就是说,当数据n增加时,我可以通过增加表长m,以维持装载因子不变,确保ASL不变。
那么hash表的构造应该是这样的:
在这里插入图片描述
(参考自https://blog.csdn.net/u011109881/article/details/80379505)

五、hash表的删除

链地址法是可以直接删除元素的;
但是开放定址法是不行的,拿前面的双探测再散列来说,假如我们删除了元素1,将其位置置空,那 23就永远找不到了。正确做法应该是删除之后置入一个原来不存在的数据,比如-1。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MySQL 中的 hash join 是一种连接两个的方法,它通过将其中一个的数据哈希到内存中的哈希来实现。另一个的数据在哈希上进行匹配,从而得到符合条件的行。 这种方法适用于其中一个的数据量较小的情况。因为哈希的查询速度很快,所以这种方法效率高。但是,如果其中一个的数据量很大,则需要将整个加载到内存中,这可能会导致内存不足。 在 MySQL 中,使用 INNER JOIN、LEFT JOIN 或 RIGHT JOIN 关键字可以实现 hash join 操作。 ### 回答2: MySQL的hashJoin是一种关联查询的算法,用于将两个中的数据进行关联。它通过计算每个的关联列的哈希值,将相同哈希值的记录分配到同一个哈希桶中,然后对每个哈希桶进行内存中的关联操作。 首先,hashJoin需要将两个要关联的按照关联列进行哈希分区。然后,对于第一个的每个分区,将其哈希列值与第二个进行匹配。如果哈希值相同,则将两个记录进行关联,生成结果。 hashJoin的优点是在内存充足的情况下,处理大规模数据的效率较高。由于哈希是在内存中构建的,所以可以减少磁盘I/O的开销。此外,它适用于多种关联类型,如内连接、左连接、右连接等。 然而,hashJoin也有一些限制。首先,它需要将整个进行哈希分区,因此在内存不足的情况下,可能导致性能下降。其次,在进行哈希分区和关联操作时,需要消耗较多的CPU资源。此外,如果两个中的关联列不具有相同的数据分布,可能导致哈希桶不均匀,进而影响关联操作的效率。 总的来说,MySQL的hashJoin算法是一种高效的关联查询方法,可以在合适的场景下提供较好的性能。但需要注意配置合适的内存大小,并保证关联列的数据分布较为均匀,以达到最佳的运行效果。 ### 回答3: MySQL中的hashJoin是一种用于联接操作的算法。联接操作是将多个中的数据按照某些条件进行匹配和合并的过程。而hashJoin是其中一种高效的联接算法。 hashJoin的原理是利用哈希的特性,在内存中构建一个哈希来存储较小中的数据。首先,将待联接的两个中的一个的数据读入内存并构建哈希,将哈希的键值设为联接条件的键值,并将相应的数据行存储在哈希中。然后,遍历另一个的数据,对于每一行数据,通过联接条件的键值查找哈希中是否存在对应的数据行,如果存在,则将两行数据进行合并,并输出结果。 相比于其他联接算法,hashJoin的优点主要体现在以下几个方面: 1. 内存控制:hashJoin将较小的数据存储在内存中,避免了大规模的磁盘读写操作,提高了查询效率。同时,由于使用哈希存储数据,可以大幅度减少内存的占用空间。 2. 快速查找:哈希的查找操作具有快速的特性,可以在常数时间内完成查找操作。这使得hashJoin能够在较短的时间内完成联接操作,适用于处理大规模数据的场景。 3. 并行化处理:由于hashJoin的哈希是在内存中构建的,可以方便地进行并行化处理。可以将不同的数据分配给不同的CPU进行处理,提高了联接操作的并行度和效率。 需要注意的是,hashJoin算法对内存的需求较高,如果内存不足,可能会导致性能下降或者无法完成联接操作。此外,选择合适的联接条件和恰当的索引也会对hashJoin的效率产生影响。因此,在使用hashJoin时,需要根据具体的业务场景和数据特点进行调优和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值