一文理清哈希(散列)表

引子

为什么有哈希表?因为在很多场景下,对这种数据结构是由应用需求的,比如在编译阶段,需要形成对变量及其属性的有效管理,这样才能判断一些操作是否合法(比如数据是否重复定义,数据类型是否合法等),再比如一些应用设计字符串的比较,相比于数字比较,这种成本是增加的,那么是否可以把字符串转化为数字,再做处理呢?

这些问题都可以在学习散列表的过程中逐步解答。

正文

铺垫

先复盘一下已知的查找方法:
在这里插入图片描述
这里给出一个非常有趣的实际例子,登录qq时,服务器是如何快速在庞大的用户群中找到你的信息并快速核对的呢?
如果用二分法这种静态查找的方法的话,可以得出,
在这里插入图片描述
所以适应这种场景下的数据结构无疑等待着一个高效且动态的(随时可以添加/删除记录的)数据结构,再引出之前,我们先探讨一下查找的本质,那就是根据对象找到他的位置,这样就有两种思路:

  • 有序安排对象,可以是全序(数组等)或者半序(查找树)
  • 直接”算出“对象的位置,引出散列

基本介绍

散列表基本工作:
在这里插入图片描述
但是复杂度与函数计算和冲突有关。

哈希冲突

这里再引出一个哈希冲突的概念
在这里插入图片描述
有冲突怎么办呢?后来冲突的元素就没有位置了,直观想法是用二维数组,增加一个位置存放元素。但是这种缓解是有限的,如何有效解决呢?这就需要设计一个”好“的散列函数。一般满足下列条件:
在这里插入图片描述

哈希函数

  • 直接定址法在这里插入图片描述

  • 除留余数法
    在这里插入图片描述

  • 数字分析法

比如身份证后几位比较随机
在这里插入图片描述

  1. 折叠法/平方取中法
    在这里插入图片描述

如果关键词是字符又该如何处理呢?

  1. ASC码加和法
    在这里插入图片描述
    但是范围太窄,很多哈希冲突,可以改进:
    在这里插入图片描述
    以下是一段很巧妙的快速计算代码,可以研究下:
    在这里插入图片描述

冲突处理方法

通常遇到冲突,常见思路有两种:

  1. 换个位置再存(开放地址法)
    在这里插入图片描述

1. 线性探测

在这里插入图片描述
缺点是很容易连续冲突,不断试探位置,最后在冲突的地方越积累越多,最后造成冲突聚集现象。可以通过下图理解。在这里插入图片描述
散列表的性能分析可以通过成功平均查找长度(即是比较次数且最后找到了)ASLs和不成功平均查找长度ASLu(即是比较次数且最后没找到)评价。

1. 平方探测

直观理解也能预期分布更均匀,观察下表一系列值存入哈希表的过程:
在这里插入图片描述

它的缺点是,可能空间不会充分利用,有些空间永远探测不到。但是他的优点是缓解了冲突聚集问题。

双散列探测法

其中di为探测偏移量。
在这里插入图片描述

  1. 同一位置的冲突对象可以组织在同一个单链表中(链地址法)
    在这里插入图片描述

性能分析

在这里插入图片描述

应用

把握住一个重点,适合哈希查找的问题都是需要高效查找的并且多是动态的。

1. 词频统计(利用哈希查找快速查找和插入)

在这里插入图片描述
实现代码如下:
在这里插入图片描述

2. 找出”电话狂人“(出现频率最高的手机号)

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41896265/article/details/108425506