哈希函数和哈希表

哈希函数和哈希表哈希函数和哈希表 1 什么是哈希函数它是一种映射关系 它可以把任意长度的输入映射到任意一个固定长度的整数值 也称为散列函数 其值是十六进制的数 说白了 哈希函数就是用来将 key value 结构中关键字值转换为数组的下标的函数 一般都是通过取模 而且这样子在数据量很大的情况下一般是均匀分布的 然后将该结构存放到数组中去 然后这个数组就叫做哈希表 这个固定长度不是说所有长度的输入获取到的整数

哈希函数和哈希表

1. 什么是哈希函数

它是一种映射关系,它可以把任意长度的输入映射到任意一个固定长度的整数值,也称为散列函数,其值是十六进制的数。

说白了,哈希函数就是用来将key-value结构中关键字值转换为数组的下标的函数(一般都是通过取模,而且这样子在数据量很大的情况下一般是均匀分布的),然后将该结构存放到数组中去,然后这个数组就叫做哈希表.

这个固定长度不是说所有长度的输入获取到的整数永远是一个长度,我觉得有两种理解:

  1. 它是说比如String str = "abc"和String str1 = "def",那它俩这种同一类型的且长度相同的获取到的是整数的位数是一般一样的;
  2. 比如说String str= "abc",当你输入参数固定的情况下,你不管运行多少回,这个字符串的哈希值是一定的,即输入一样,输出一定一样;
  3. 当然这里有个特殊的东西:那就是比如说String str = new String("abc"),这个你重复运行后生成的哈希值是不一样的,因为每次重复运行生成的都是一个新的对象.

这个你可以用hashCode()方法测试,你输入多个长度相同的string类型的字符串,看看输出的是不是都是十六进制的相同长度的整数就可以了.

特殊情况: 由于输入域是无穷的,但是输出域范围是有限的(它是16位的,每个位置都有16个数,一共只有16^16个数,即范围为 – 2^64 ~ 2^64-1),所以一定会出现不同的输入域但是得到了同一个输出,这就叫哈希冲突.

2. 什么是哈希表

哈希表(hash table,也叫散列表)是根据关键码值(Key value中的key)而直接进行访问的数据结构,也就是说: 哈希表基于数组,其中每个单元都是类似于key-value的存储形式关键字值通过哈希函数映射为数组的下标,如果一个关键字哈希化(将关键字转换为数组下标的过程)后映射到一个已占用的数组单元,这种情况就是上面的哈希冲突。

3. 如何解决哈希冲突

  1. 开发地址法:

开放地址法的思路就是: 通过系统的方法找到数组的一个空位,并把这个元素填进去,就不再用哈希函数获得的数组下标,它有三种方法:

  1. 线性探测
    线性探测的思路: 它会线性的查找空白单元.
    比如说5421是哈希函数计算出来的下标,但是它已经被占用了,那它就去使用5422,如果5422也被使用了,那它就去使用5423,以此类推,它的数组下标会一直递增,知道找到空白的位置.
    但是这会有一个问题: 那就是当哈希表太满的时候,我们每插入一个数据,都要频繁的探测插入位置,因为可能很多位置都被前面插入的数据占用了,这就称为聚集


  2. 二次探测(解决聚集)
    二次探测的思想: 探测相距较远的单元,而不是和原始位置相邻的单元.
    比如说: 如果哈希函数计算的原始下标是x,线性探测就是x+1,x+2,x+3这样子类推下去,而在二次探测中,探测的过程是x+1, x+4,x+9,x+16这样子,到原始位置的距离是步数的平方.这样子可以很好的解决线性探测带来的聚集问题.
    但是这会产生一个新的问题:这个问题叫做二次聚集,比如说184,552,336,753依次插入表中,他们通过哈希函数计算出来的下标都是7,按照上面的规律,552就放在8,336需要放在11,753需要放在17这样子,后面再有要放在下标为7的元素的话,它就要往后面移动更长的距离.


  3. 再哈希法(解决二次聚集)
    由于二次聚集的原因是因为每次移动的长度有规律的:1,4,9,16,25这样子,那么解决方法就是找到一种依赖于关键字的探测序列,那么就可以做到每个关键字移动的方法就都不一样了,即把关键字通过不同的哈希函数再做一遍哈希化,用这个结果作为步长,每次移动步长个距离,虽然步长对于每个关键字来说是一定的,但是不同关键字的步长是不一样的.
    为了实现想要的效果,第二个哈希函数必须有以下几个特点:
    1. 和第一个哈希函数不能相同.
    2. 不能输出0,输出0就永远在原地踏步,就死循环了.



2.链地址法:

链地址法的思路: 把哈希表每个单元中的存储方式都设置为链表,某个数据项的关键字值还是像之前一样通过哈希函数映射到哈希表,但是这个数据插入到哈希表指定下标单元的链表中,当有其他元素映射到同一个单元的时候,就往链表后面挂就可以了.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233720.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • PostgreSQL 9.6.1,9.5.5,9.4.10,9.3.15,9.2.19和9.1.24发布!

    PostgreSQL 9.6.1,9.5.5,9.4.10,9.3.15,9.2.19和9.1.24发布!

    2022年2月22日
    59
  • sqlyog13.1.6激活成功教程版_sqlyog10.0安装教程

    sqlyog13.1.6激活成功教程版_sqlyog10.0安装教程1、SQLyog-12.2.4-0.x64Trial.exe,直接去官网下载。2、修改注册表项开始-运行-regedit,进入注册表HKEY_CURRENT_USER\Software\SQLyog修改权限拒绝修改。OK,激活成功教程完成。试用14天一直可以使用下去转载于:https://www.cnblogs…

    2025年11月13日
    2
  • Fisher Yates 洗牌算法「建议收藏」

    Fisher Yates 洗牌算法「建议收藏」//经典的洗牌算法,数组中随机抽一个元素与最后一个进行交换,下次在前n-1个元素中随机抽,依次类推直到最后一个voidshuffle(CREC*array,longn){longi,j;CRECtmp;for(i=n-1;i>0;i–){j=rand_long(i+1);tmp=a

    2022年9月21日
    4
  • 本地的html源文件,本地书源导入教程

    本地的html源文件,本地书源导入教程本地书源导入教程免贵姓操•2018年05月05日请注意,本文编写于1143天前,最后修改于96天前,其中某些信息可能已经过时。0×1.单个书源导入操作步骤:复制下面的书源代码,在[书源管理]点击“+”号,然后点击右上角的3个点,选择[粘贴书源],再点击[保存],然后书源前面勾选启用即可。{“bookSourceGroup”:””,”bookSourceName”…

    2022年6月15日
    53
  • xshell6下载教程_下载软件怎么解压安装

    xshell6下载教程_下载软件怎么解压安装还饱受xhell产品各种到期侵害的同志们,可以下载使用这版,本人已经用了将近一年,不存在到期的问题。当然,如果你的机子之前就用了Xshell6且已经过期了。那就不用试了,基本也是没戏o_O,换别的版本的激活成功教程版吧~链接:https://pan.baidu.com/s/1z5wRnghMMXJBylXyH7IQRg提取码:08yd…

    2022年10月9日
    4
  • matlab运算放大器概述,运算放大器概述「建议收藏」

    matlab运算放大器概述,运算放大器概述「建议收藏」运算器的历史第一个使用真空管设计的放大器大约在1930年前后完成,这个放大器可以执行加与减的工作。运算放大器最早被设计出来的目的是将电压类比成数字,用来进行加、减、乘、除的运算,同时也成为实现模拟计算机(analogcomputer)的基本建构方块。然而,理想运算放大器的在电路系统设计上的用途却远超过加减乘除的计算。今日的运算放大器,无论是使用晶体管(transistor)或真空管(vacuum…

    2022年5月5日
    87

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号