hash表:
高效查找的数据结构,也叫做散列
散列方法是使用函数h将U映射到表T[0..m-1]的下标上(m=O(|U|))。这样以U中关键字为自变量,以h为函数的运算结果就是相应结点的存储地址。从而达到在O(1)时间内就可完成查找。
就是以地址的以地址查询的方式不断地查找映射
一种函数H,根据这个函数和查找关键字key,可以直接确定查找值所在位置,而不需要一个个比较。这样就**“预先知道”**key所在的位置,直接找到数据,提升效率。
利用哈希数组去标记哈希值,作为一个下标
求hash就是要对其取模,两个数对应到了一个数中,两个x或者是更多的x对应到了一个值
对于hash表
地址index=H(key)
和正常的数组的差别就是,这个hash函数就是根据key计算出应该存储地址的位置,这个hash函数是原本带有地址的,转化成为一个下标
实数哈希
开放寻址法:顺着数组的长度一次寻找,直到我们找到为止
哈希函数的构造方法
1.直接定制法:构造的方法相对来说比较简单
关键字k除以m,取余数作为在Hash表中的位置。函数表达式可以写成:
h(k)=k mod m 注:一般m选择为素数
对于这个哈希查找,由于是相对来说比较简单的直接取余法,这对hash,求hash就是要对其取模,两个数对应到了一个数中,两个x或者是更多的x对应到了一个值,这样可能出现的错误概率会更大一点
2.乘积取整法
关键字k乘以一个在(0,1)中的实数(最好是无理数),得到一个(0,1)之间的实数;取出其小数部分,乘以m,再取整数部分,即得K在Hash表中的位置。这样的话就减少了之前直接取值的错误概率
h(K) = [ M (KAmod1)]
3.
3、平方取中法
把关键字K平方,然后取中间的位作为Hash函数值返回。由于K的每一位都会对其平方中间的若干位产生影响,因此这个方法的效果也是不错的。但是对于比较小的K值效果并不是很理想,实现起来也比较繁琐。为了充分利用Hash表的空间,M最好取2的整数次幂。例如,表容量M=2^4=16,,关键值K=100,那么h(k)=8,平方取中的目的就是使得这个原本的关键字k的数值变得更大一点,方便对其之后进行一些相关的操作,但是如果k是一个比较小的数字,那么就会适得其反
字符串hash
我们可以去找一下
这两个字符串所对应的是否是相同的
kmp和字符串hash就可以去实现
这个字符串hash是在前缀和的思想上所实现的
字符串本身就不是一个数,而是一个字符串
所以我们可以去思考这个字符串,我们可不可以变成一个数
字符串本身就可以看成一个256进制(ANSI字符串为128进制)的大整数,因此我们可以利用直接取余法,在线性时间内直接算出Hash函数值。
为了保证效果,仍然不能选择太接近2^n的数;尤其是当我们把字符串看成一个2^p进制数的时候,选择m= 2^p -1会使得该字符串的任意一个排列的Hash函数值都相同
字符串各个字符的前缀和----字符串前缀哈希法
p进制数
把字符串abcd按照字符串的p进制展开的数
只要是hash表的问题,都会出现一个hash冲突
p可以取131或者是1331
hash的方式一般就是对于一个数进行一个相应的取模
经验之谈
字符串hash
p进制数 p 131,1331
q 取2^64
前缀和每一个数字的字母开始都是从1开始的
对于hash函数的冲突
冲突两个不同的关键字,由于散列函数值相同,因而被映 射到同一表位置上。该现象称为冲突(Collision)或碰撞。
• 安全避免冲突的条件 最理想的解决冲突的方法是安全避免冲突。要做到这一点 必须满足两个条件:
①其一是|U|≤m
②其二是选择合适的散列函数。 这只适用于|U|较小,且关键字均事先已知的情况,此 时经过精心设计散列函数h有可能完全避免冲突。
• 影响冲突的因素 冲突的频繁程度除了与h相关外,还与表的填满程度相关。设m和n分别表示表长和表中填人的结点数,则将 α=n/m定义为散列表的装填因子(Load Factor)。α越大, 表越满,冲突的机会也越大。通常取α≤1。
所以我们为了避免哈希冲突,我们就要去适当的选择这个函数