#新人扶持计划#

Hash表在面试中经常被问到,今天我们来了解下。

Hash表也称散列表,也有直接译作哈希表,Hash表是一种特殊的数据结构,它同数组、链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。这个源于Hash表设计的特殊性,它采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找。

1、Hash表的设计思想

对于一般的线性表,比如链表,如果要存储联系人信息:

张三 11111111111李四 22222222222王五 33333333333张帅 44444444444

那么可能会设计一个结构体包含姓名,手机号码这些信息,然后把4个联系人的信息存到一张链表中。当要查找”李四 22222222222“这条记录是否在这张链表中或者想要得到李四的手机号码时,可能会从链表的头结点开始遍历,依次将每个结点中的姓名同”李四“进行比较,直到查找成功或者失败为止,这种做法的时间复杂度为O(n)。即使采用二叉排序树进行存储,也最多为O(logn)。假设能够通过”李四“这个信息直接获取到该记录在表中的存储位置,就能省掉中间关键字比较的这个环节,复杂度直接降到O(1)。Hash表就能够达到这样的效果。

Hash表采用一个映射函数 f : key —> address 将关键字映射到该记录在表中的存储位置,从而在想要查找该记录时,可以直接根据关键字和映射关系计算出该记录在表中的存储位置,通常情况下,这种映射关系称作为Hash函数,而通过Hash函数和关键字计算出来的存储位置(注意这里的存储位置只是表中的存储位置,并不是实际的物理地址)称作为Hash地址。比如上述例子中,假如联系人信息采用Hash表存储,则当想要找到“李四”的信息时,直接根据“李四”和Hash函数计算出Hash地址即可。

Hash函数设计的好坏直接影响到对Hash表的操作效率。

比如对上述的联系人信息进行存储时,采用的Hash函数为:姓名的每个字的拼音开头大写字母的ASCII码之和。

address(张三)=ASCII(Z)+ASCII(S)=90+83=173;

address(李四)=ASCII(L)+ASCII(S)=76+83=159;

address(王五)=ASCII(W)+ASCII(W)=87+87=174;

address(张帅)=ASCII(Z)+ASCII(S)=90+83=173;

假如只有这4个联系人信息需要进行存储,这个Hash函数设计的很糟糕。首先,它浪费了大量的存储空间,空间利用率只有4/174,不到5%;另外,根据Hash函数计算结果之后,address(张三)和address(李四)具有相同的地址,这种现象称作Hash冲突,对于174个存储空间中只需要存储4条记录就发生了冲突,这样的Hash函数设计是很不合理的。所以在构造Hash函数时应尽量考虑关键字的分布特点来设计函数使得Hash地址随机均匀地分布在整个地址空间当中。

通常有以下几种构造Hash函数的方法:

① 直接定址法

取关键字或者关键字的某个线性函数为Hash地址,即address(key)=a*key+b;如知道学生的学号从2000开始,最大为4000,则可以将address(key)=key-2000作为Hash地址。

② 平方取中法

对关键字进行平方运算,然后取结果的中间几位作为Hash地址。假如有以下关键字序列{421,423,436},平方之后的结果为{177241,178929,190096},那么可以取{72,89,00}作为Hash地址。

③ 折叠法

将关键字拆分成几部分,然后将这几部分组合在一起,以特定的方式进行转化形成Hash地址。假如知道图书的ISBN号为8903-241-23,可以将address(key)=89+03+24+12+3作为Hash地址。

④ 除留取余法

如果知道Hash表的最大长度为m,可以取不大于m的最大质数p,然后对关键字进行取余运算,address(key)=key%p。在这里p的选取非常关键,p选择的好的话,能够最大程度地减少冲突,p一般取不大于m的最大质数。

2、Hash表大小的确定

Hash表大小的确定也非常关键,如果Hash表的空间远远大于最后实际存储的记录个数,则造成了很大的空间浪费,如果选取小了的话,则容易造成冲突。在实际情况中,一般需要根据最终记录存储个数和关键字的分布特点来确定Hash表的大小。还有一种情况时可能事先不知道最终需要存储的记录个数,则需要动态维护Hash表的容量,此时可能需要重新计算Hash地址。

3、冲突的解决

在上述例子中,发生了冲突现象,因此需要办法来解决,否则记录无法进行正确的存储。通常情况下有2种解决办法:

① 开放定址法

即当一个关键字和另一个关键字发生冲突时,使用某种探测技术在Hash表中形成一个探测序列,然后沿着这个探测序列依次查找下去,当碰到一个空的单元时,则插入其中。比较常用的探测方法有线性探测法,比如有一组关键字{12,13,25,23,38,34,6,84,91},Hash表长为14,Hash函数为address(key)=key%11,当插入12,13,25时可以直接插入,而当插入23时,地址1被占用了,因此沿着地址1依次往下探测(探测步长可以根据情况而定),直到探测到地址4,发现为空,则将23插入其中。

② 链地址法

采用数组和链表相结合的办法,将Hash地址相同的记录存储在一张线性表中,而每张表的表头的序号即为计算得到的Hash地址。如上述例子中,采用链地址法形成的Hash表存储表示为:

虽然能够采用一些办法去减少冲突,但是冲突是无法完全避免的。因此需要根据实际情况选取解决冲突的办法。

4、Hash表的平均查找长度

Hash表的平均查找长度包括查找成功时的平均查找长度和查找失败时的平均查找长度。

查找成功时的平均查找长度=表中每个元素查找成功时的比较次数之和/表中元素个数;查找不成功时的平均查找长度相当于在表中查找元素不成功时的平均比较次数,可以理解为向表中插入某个元素,该元素在每个位置都有可能,然后计算出在每个位置能够插入时需要比较的次数,再除以表长即为查找不成功时的平均查找长度。

这里有一个概念装填因子=表中的记录数/哈希表的长度,如果装填因子越小,表明表中还有很多的空单元,则发生冲突的可能性越小;而装填因子越大,则发生冲突的可能性就越大,在查找时所耗费的时间就越多。因此,Hash表的平均查找长度和装填因子有关。有相关文献证明当装填因子在0.5左右的时候,Hash的性能能够达到最优。因此,一般情况下,装填因子取经验值0.5

5、Hash表的优缺点

Hash表存在的优点显而易见,能够在常数级的时间复杂度上进行查找,并且插入数据和删除数据比较容易。但是它也有某些缺点,比如不支持排序,一般比用线性表存储需要更多的空间

本篇理论性较强,需要结合工作中的实践加深理解。

e - 数据结构实验之查找五:平方之哈希表_面试中常被问到的Hash表,你了解吗相关推荐

  1. e - 数据结构实验之查找五:平方之哈希表_leetcode算法之哈希表

    今天该来盘一盘 哈希表 这类题目 分类别解析leetcode上的一些相关的例题路,代码采用C++与python实现. 哈希表 哈希表是一种很有用的数据结构, 其作用主要是以空间换时间, 在c++中主要 ...

  2. SDUT 3377 数据结构实验之查找五:平方之哈希表

    数据结构实验之查找五:平方之哈希表 Time Limit: 400MS Memory Limit: 65536KB Submit Statistic Problem Description 给定的一组 ...

  3. E数据结构实验之查找五:平方之哈希表

    Description 给定的一组无重复数据的正整数,根据给定的哈希函数建立其对应hash表,哈希函数是H(Key)=Key%P,P是哈希表表长,P是素数,处理冲突的方法采用平方探测方法,增量di=± ...

  4. 数据结构实验之查找五:平方之哈希表

    题目描述 给定的一组无重复数据的正整数,根据给定的哈希函数建立其对应hash表,哈希函数是H(Key)=Key%P,P是哈希表表长,P是素数,处理冲突的方法采用平方探测方法,增量di=±i^2,i=1 ...

  5. 面试:整理面试中常被问到的8种数据结构

    数据结构是一种特殊的组织和存储数据的方式,可以使我们可以更高效地对存储的数据执行操作.数据结构在计算机科学和软件工程领域具有广泛而多样的用途. 几乎所有已开发的程序或软件系统都使用数据结构.此外,数据 ...

  6. 面试中常被问到(13)五种IO模型

    阻塞IO: 发起IO调用,若发现IO未就绪(IO条件不具备),则一直等待  也就说条件不满足一直死等 非阻塞IO: 发起IO调用,若发现IO未就绪,则直接报错返回 应用程序通过recvfrom调用不断 ...

  7. 面试中常被问到(五)C++析构函数,虚析构函数

    C++析构函数 (1)对于析构函数:析构函数与构造函数相呼应,从调用构造函数开始到自动执行析构函数二者调用期间即为所创建对象实例的生命周期. (2)析构函数与类名相同,仅前面加一个~,一般析构函数无参 ...

  8. 数据结构实验之链表五:单链表的拆分-sdut

    数据结构实验之链表五:单链表的拆分 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 输入N个 ...

  9. SDUT-3378_数据结构实验之查找六:顺序查找

    数据结构实验之查找六:顺序查找 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 在一个给定的无序序列里,查找与给定关键字 ...

最新文章

  1. 原来,苹果一直在给自家应用开防火墙绿灯!
  2. python字典遍历的4种方法
  3. overload override
  4. Hbase(1)——基础语句(1)
  5. freemarker -自定义指令
  6. uni-app 2.2 发布,大幅度优化 H5 端性能体验 | 技术头条
  7. 公众号回复单个图文消息
  8. ifconfig 命令,改变主机名,改DNS hosts、关闭selinux firewalld netfilter 、防火墙iptables规则...
  9. vue+django实现下载文件
  10. 力扣刷题 | 二叉树专题
  11. 王炸 | 海康汽车来了 商机还是冒进?
  12. 互联网行业中最常用的数据库——MySQL数据库介绍
  13. Clion 配置 opencv不显示图片Process finished with exit code -1073741515 (0xC0000135)
  14. matlab绘制蜗牛圈圈图,Matlab实现的图像中的圆、矩形、正方形等形状识别
  15. Win10系统文件名太长导致无法删除
  16. java引_JAVA中的引用
  17. Android卡顿掉帧问题分析之工具篇
  18. 理解浏览器的多线程,JavaScript的单线程
  19. 第一次尝试使Windows Live Writer发布日志
  20. 东大19春计算机基础,东大19春学期《计算机基础》在线作业3标准答案.doc

热门文章

  1. 通过零拷贝进行有效的数据传输(java、c)
  2. FD.io VPP 20.05 官方文档 总目录:用户文档+开发文档+命令行
  3. NUMA全称 Non-Uniform Memory Access,译为“非一致性内存访问”,积极NUMA内存策略
  4. DPDK单生产者入队单消费者出队
  5. 创建一个SQL测试数据库 - 消费者数据库
  6. mybatis ------ 逆向工程(十)
  7. linux通过vnc掉出浏览器,VNC远程Linux桌面控制好用 --尤其是用浏览器
  8. mac pycharm 卸载_Mac上Virtual Box虚拟机Linux系统安装
  9. agaular 离线文档_Zeal 国外一款面向开发者的离线文档查看工具
  10. oracle 日期 加一秒,Leap Second (闰秒) 在ORACLE环境的影响