数据结构-哈希表

哈希表

一般构造哈希表有两种重要的方法:开放寻址法和拉链法
哈希表是一种期望算法,一般情况下,复杂度都可以看成o(1)
在算法题中,一般对哈希表只要求有添加和查找两种操作。就算要实现删除,也就是开个新数组,然后打个标记。
1.直接取模(一般要mod一个质数)
2.解决冲突:拉链法,如果11存到了3,23也存到了3,那么会用一条链,把其都存在3下面。

模拟散列表

哈希表也叫散列表
常见的散列函数:
1.直接定址法:适用场景:必须事先知道关键字,关键字(key)集合不是很大,且连续性较好。
2.除留余数法:最简单和最常用的构造散列函数的方法,并且不需要事先知道关键字的分布。
这种方法,一般 hash(key) = key % p ,通常,假定散列表的表长为m取一个不大于表长的最大素数p。为什么要取素数,此处略。
但是不管怎么样设计散列函数,都无法避免冲突的问题,发生冲突时,需要进行冲突处理,主要有三种方法,这里着重介绍开放地址法还有链地址法(拉链法)。

开放地址法

开放地址法是在线性存储空间上的解决方案,称为闭散列。开放地址法在发生冲突时,会在线性存储空间上探测其它位置,也就是说会继续在这行线性的空间上,找空的位置插入元素。其可以用如下公式来概括:hash’(key) = (hash(key) + di) % m(注意:此处的m为表长
其中,hash(key)为原散列函数,hash’(key)为探测函数,di为增量序列(通过当前位置加上增强序列可以确定下一次需要探测的位置)。
那么,根据 增量序列的不同,开放地址法又可以分为,线性探测法、二次探测法、随即探测法、再散列法。这里着重介绍一下线性探测法和二次探测法。

线性探测法:

最简单的开放地址法,其增量序列范围为 [1, m-1]。
下面举例说明,如有一组关键字(14, 36, 42, 38, 40, 15, 19, 12, 51, 65, 34, 25),若表长为15,散列函数为 hash(key) = key % 13,采用线性探测法处理冲突,构造散列表。

哈希地址01234567891011121314
关键字651440415251936381251
比较次数11213911123
  • 首先,hash(key) = key % 13,即14 % 13 = 1, 那么查找哈希地址为1处,为空,则填入14。
  • 然后,36 % 13 = 10,那么查找哈希地址为10处,为空,则填入36。
  • 然后,42 % 13 = 3,那么查找哈希地址为3处,为空,则填入42。
  • 然后,38 % 13 = 12,那么查找哈希地址为12处,为空,则填入38。
  • 然后,40 % 13 = 1,那么查找哈希地址为1处,发现此处不为空
    • 那么此时 执行我们的 hash’(key) = (hash(key) + di) % 15,则为 (1 + 1) % 15 = 2(其实就是接着往下探测一位),那么查找哈希地址为2处,为空,则填入40。
  • 然后,15 % 13 = 0,那么查找哈希地址为2处,不为空,
    • 那么,执行 hash’(key) = (hash(key) + di) % 15,则为 (2 + 1) % 15 = 3(原来探测的是下标2的位置,然后再继续探测3的位置),那么查找哈希地址为3处,不为空。
      • 那么,di++,hash’(key) = (hash(key) + di) % 15,则为 (2 + 2) % 15 = 4(其实就是接着再往下探测一位),查找哈希地址为4处,为空,则填入15,比较次数为3。
  • 然后,19 % 13 = 6,那么查找哈希地址为6处,为空,则填入19。
  • 然后,12 % 13 = 12,那么查找哈希地址为12处,不为空,…,接着往下探测一位
    • 那么,那么查找哈希地址为13处,为空,填入12,比较次数为2。
  • 然后,51 % 13 = 12,那么查找地址为12处,不为空,同上可知,继续,查找地址为13处,不为空,继续,查找地址14处,为空,则填入51,比较次数为3。
  • 然后,65 % 13 = 0,那么查找地址为0处,为空,填入65。
  • 然后34 % 13 = 7,那么查找地址为7处,为空,填入34。
  • 然后25 % 13 = 12,那么查找地址为12处,不为空,继续查找,地址为13处(此时di=1),也不为空,继续查找,地址为14处(此时di=2),也不为空,可是此时继续往下查找则溢出了,此时根据我们刚才的 hash’(key) = (hash(key) + di) % 15,此时di = 2 + 1 = 3,接下来要找的位置为 (12 + 3) % 15 = 0,则也就是继续从0开始探测,地址0处不为空,则继续探测,直到发现地址为5处,为空,则填入25,此时比较次数为9。
  • (比较次数可以理解为找了多少个位置进行探测)
二次探测法:

采用前后跳跃式探测的方法,发生冲突时,按照 向后1位探测,向前1位,向后2位探测,向前2位探测,以此类推,跳跃式探测,直到解决冲突。
下面举例说明,如:一组关键字 (14, 36, 42, 38, 40, 15, 19, 12, 51, 65, 34, 25),若表长为15,散列函数 hash(key) = key % 5,采用二次探测法处理冲突。

哈希地址01234567891011121314
关键字6514404215193436513812
比较次数11214211312

过程与线性探测法类似,只不过每次发生冲突时,增量序列有所不同,此处分析略。

拉链法

线性探测法效率低于拉链法。
拉链法也就是,如果不同关键字通过散列函数映射到同一地址时,此时,这些关键字称为同义词,将所有同义词存储在一个线性链表中,拉链法适用于经常进行插入、删除的情形。
也就是在每个地址下,都可以对映射到此处的关键字进行链式存储。
如:一组关键字 (14, 36, 42, 38, 40, 15, 19, 12, 51, 65, 34, 25),若表长为15,散列函数 hash(key) = key % 5,采用拉链法处理冲突,如下图所示:
image.png

字符串哈希

暂时略。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值