Java学数据结构(4)——散列表Hash table 散列函数 哈希冲突

目录

  • 引出
  • 散列表Hash table
  • 关键字Key和散列函数(hash function)
  • 散列函数
  • 解决collision哈希冲突(碰撞)
    • 分离链接法(separate chaining)
    • 探测散列表(probing hash table)
    • 双散列(double hashing)
  • Java标准库中的散列表
  • 总结

引出


1.散列表,key,散列函数;
2.哈希冲突的解决;
3.string中的hashCode;

在这里插入图片描述

散列表Hash table

查找树ADT,它允许对元素的集合进行各种操作。本章讨论散列表(hash table)ADT,不过它只支持二叉查找树所允许的一部分操作。散列表的实现常常叫作散列(hashing)。散列是一种用于以常数平均时间执行插入、删除和查找的技术。但是,那些需要元素间任何排序信息的树操作将不会得到有效的支持。因此,诸如findMin、findMax以及以线性时间将排过序的整个表进行打印的操作都是散列所不支持的。

  • 看到实现散列表的几种方法。
  • 解析地比较这些方法。
  • 介绍散列的多种应用。
  • 将散列表和二叉查找树进行比较。

关键字Key和散列函数(hash function)

理想的散列表数据结构只不过是一个包含一些项(itm)的具有固定大小的数组。通常查找是对项的某个部分(即数据域)进行的。这部分就叫作关键字(key)

例如,项可以由一个字符串(它可以作为关键字)和其他一些数据域组成(例如,姓名是大型雇员结构的一部分)。我们把表的大小记作TableSize,并将其理解为散列数据结构的一部分,而不仅仅是浮动于全局的某个变量。通常的习惯是让表从0到TableSize-1变化;稍后我们就会明白为什么要这样做。

每个关键字被映射到从0到TableSize-1这个范围中的某个数,并且被放到适当的单元中。这个映射就叫作散列函数(hash function),理想情况下它应该计算起来简单,并且应该保证任何两个不同的关键字映射到不同的单元。不过,这是不可能的,因为单元的数目是有限的,而关键字实际上是用不完的。因此,我们寻找一个散列函数,该函数要在单元之间均匀地分配关键字。

图5-1是完美情况的一个典型。在这个例子中,john散列到3,phil散列到4,dave散列到6,mary散列到7。

在这里插入图片描述

这就是散列的基本想法。剩下的问题就是要选择一个函数,决定当两个关键字散列到同一个值的时候(这叫作冲突(collision))应该做什么以及如何确定散列表的大小。

散列函数

在这里插入图片描述

这个散列函数利用到事实:允许溢出。这可能会引进负的数,因此在末尾有附加的测试。图5-4所描述的散列函数就表的分布而言未必是最好的,但确实具有极其简单的优点而且速度也很快。如果关键字特别长,那么该散列函数计算起来将会花费过多的时间。在这种情况下通常的经验是不使用所有的字符。此时关键字的长度和性质将影响选择。例如,关键字可能是完整的街道地址,散列函数可以包括街道地址的几个字符,也许还有城市名和邮政编码的几个字符。有些程序设计人员通过只使用奇数位置上的字符来实现他们的散列函数,这里有这么一层想法:用计算散列函数节省下的时间来补偿由此产生的对均匀地分布的函数的轻微干扰。

在这里插入图片描述

解决collision哈希冲突(碰撞)

剩下的主要编程细节是解决冲突的消除问题。如果当一个元素被插入时与一个已经插入的元素散列到相同的值,那么就产生一个冲突,这个冲突需要消除。解决这种冲突的方法有几种,我们将讨论其中最简单的两种:分离链接法和开放定址法。

分离链接法(separate chaining)

分离链接法(separate chaining)

解决冲突的第一种方法通常叫作分离链接法(separate chaining),其做法是将散列到同一个值的所有元素保留到一个表中。我们可以使用标准库表的实现方法。如果空间很紧,则更可取的方法是避免使用它们(因为这些表是双向链接的并且浪费空间)。本节我们假设关键字是前10个完全平方数并设散列函数就是hash(x)=xmod10(表的大小不是素数,用在这里是为了简单)。

在这里插入图片描述

探测散列表(probing hash table)

探测散列表(probing hash table)

在这里插入图片描述

分离链接散列算法的缺点是使用一些链表。由于给新单元分配地址需要时间(特别是在其他语言中),因此这就导致算法的速度有些减慢,同时算法实际上还要求对第二种数据结构的实现。另有一种不用链表解决冲突的方法是尝试另外一些单元,直到找出空的单元为止。更常见的是,单元h(x),h,(x),h2(x),…相继被试选,其中h:(x)=(hash(x)+f(i)mod
TableSize,且f(0)=0。函数f是冲突解决方法。因为所有的数据都要置入表内,所以这种解决方案所需要的表要比分离链接散列的表大。一般说来,对于不使用分离链接的散列表来说,其装填因子应该低于入=0.5。我们把这样的表叫作探测散列表(probing hash table)。现在我们就来考察三种通常的冲突解决方案。

在这里插入图片描述

第一个冲突在插人关键字49时产生;它被放入下一个空闲地址,即地址0,该地址是开放的。关键字58先与18冲突,再与89冲突,然后又和49冲突,试选三次之后才找到一个空单元。对69的冲突用类似的方法处理。只要表足够大,总能够找到一个自由单元,但是如此花费的时间是相当多的。更糟的是,即使表相对较空,这样占据的单元也会开始形成一些区块,其结果称为一次聚集(primary clustering),就是说,散列到区块中的任何关键字都需要多次试选单元才能够解决冲突,然后该关键字被添加到相应的区块中。

平方探针

平方探测是消除线性探测中一次聚集问题的冲突解决方法。平方探测就是冲突函数为二次的探测方法。流行的选择是f(i)=i**2。图5-13显示与前面线性探测例子相同的输人使用该冲突函数所得到的散列表。

在这里插入图片描述

当49与89冲突时,其下一个位置为下一个单元,该单元是空的,因此49就被放在那里。此后,58在位置8处产生冲突,其后相邻的单元经探测得知发生了另外的冲突。下一个探测的单元在距位置8为2=4远处,这个单元是个空单元。因此,关键字58就放在单元2处。对于关键字69,处理的过程也一样。

虽然平方探测排除了一次聚集,但是散列到同一位置上的那些元素将探测相同的备选单元。这叫作二次聚集(secondary clustering)。二次聚集是理论上的一个小缺憾。模拟结果指出,对每次查找,它一般要引起另外的少于一半的探测。下面的技术将会排除这个缺撼,不过这要付出计算一个附加的散列函数的代价。

双散列(double hashing)

在这里插入图片描述

我们将要考察的最后一个冲突解决方法是双散列(double hashing)。对于双散列,一种流行的选择是f(i)=i·hash2(x)。这个公式是说,我们将第二个散列函数应用到x并在距离hash2(x),2hash(x),…等处探测。hash2(x)选择得不好将会是灾难性的。例如,若把99插入到前面例子中的输入中去,则通常的选择hash2(x)=xmod9将不起作用。因此,函数一定不要算得0值。另外,保证所有的单元都能被探测到也是很重要的(但在下面的例子中这是不可能的,因为表的大小不是素数)。诸如hash2(x)=R-(x mod R)这样的函数将起到良好的作用,其中R为小于TableSize的素数。如果我们选择R=7,则图5-18显示插入与前面相同的一些关键字的结果。

第一个冲突发生在49被插入的时候。hash2(49)=7-0=7,故49被插入到位置6。hash2(58)7-2=5,于是58被插人到位置3。最后,69产生冲突,从而被插入到距离为hash2(69)=7-6=1远的地方。如果我们试图将60插入到位置0处,那么就会产生一个冲突。由于hash2(60)=74=3,因此我们尝试位置3、6、9,然后是2,直到找出一个空的单元。一般是有可能发现某个坏

在这里插入图片描述

Java标准库中的散列表

标准库包括Set和Map的散列表的实现,即HashSet类和HashMap类。HashSet中的项(或HashSet中的关键字)必须提供equals方法和hashCode方法,如较早我们在节5.3所描述的那样。HashSet和HashMap通常是用分离链接散列实现的。

如果这些表项是否可以依有序方式查看这一点并不重要,那么这些类可以使用。例如,在4.8节的单词变换例子中,存在三种映射:

1.其中关键字为单词长度(word length),而关键字的值是长为该单词长度的所有单词的集合。

2.关键字是一个代表(representative),而关键字的值是具有该代表的所有单词的集合。

3.关键字是一个单词(wod),而关键字的值是与该单词只有一个字母不同的所有单词的集合。

因为单词长度被处理的顺序并不重要,所以第1个映射可以是HashMap。而由于第2个映射建立以后甚至不需要代表,因此第2个映射也可以是HashMap。第3个映射还可以是HashMap,除非我们想要printHighChangeables依字母顺序列出单词的子集(这些单词可以被变换成许多其他单词)。

HashMap的性能常常优于TreeMap的性能,不过不按这两种方式编写代码很难有把握肯定。因此,在HashMap或TreeMap可以接受的情况下,更可取的方法是:使用接口类型Map进行变量的声明,然后,将TreeMap的实例变成HashMap的实例并进行计时测试。

在Java中,能够被合理地插人到一个HashSet中去或是所谓关键字被插入到HashMap中去的那些库类型已经被定义了equals和hashCode方法。

特别是String类中有一个hashCode方法。

在这里插入图片描述


总结

1.散列表,key,散列函数;
2.哈希冲突的解决;
3.string中的hashCode;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/94624.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ssm+vue校园活动管理平台源码和论文

ssmvue校园活动管理平台源码和论文090 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 使用旧方法对校园活动信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在校园活动信…

DPI 设置和获取

DPI设置与获取之前请保证程序已经打开DPI感知或者在清单文件嵌入DPI感知,否则API可能获取的值不准确 方法一:GetScaleFactorForMonitor 通过枚举显示器获取不同设备的DPI,获取的是实际DPI static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,HDC…

华为数通方向HCIP-DataCom H12-821题库(单选题:101-120)

第101题 可用于多种路由协议,由 ​​if-match​​​和 ​​apply​​子句组成的路由选择工具是 A、​​route-policy​​ B、​​IP-Prefix​​ C、​​commnityfilter​​ D、​​as-path-filter​​ 答案:A 解析: Route-policy(路由策…

【进阶篇】MySQL 存储引擎详解

文章目录 0.前言1.基础介绍2.1. InnoDB存储引擎底层原理InnoDB记录存储结构和索引页结构InnoDB记录存储结构:InnoDB索引页结构: 3. MVCC 详解3.1. 版本号分配:3.2. 数据读取:3.3. 数据写入:3.4. 事务隔离级别&#xff…

Jenkins 详细安装流程及填坑记录「图文」

目录 一、前言 二、环境准备 三、安装步骤 1、安装jdk 2、安装jenkins 3、配置修改 4、jenkins启动 四、登录jenkins 一、前言 省流:本文仅记录Jenkins详细安装过程,以及安装过程中经常遇到的问题。 二、环境准备 Linux系统:CentOS…

基于Spring实现博客项目

访问地址:用户登录 代码获取:基于Spring实现博客项目: Spring项目写博客项目 一.项目开发 1.项目开发阶段 需求评审,需求分析项目设计(接口设计,DB设计等,比较大的需求,需要设计流程图,用例图,UML, model中的字段)开发+自测提测(提交测试…

网易新财报:游戏稳、有道进、云音乐正爬坡

今年以来,AI大模型的火热程度屡屡攀升,越来越多的企业都加入到了AI大模型的赛场中,纷纷下场布局。而在众多参与者中,互联网企业的身影更是频频浮现,比如,百度、阿里巴巴、腾讯等等。值得一提的是&#xff0…

同态比较算法

参考文献: [PS73] Paterson M S, Stockmeyer L J. On the number of nonscalar multiplications necessary to evaluate polynomials[J]. SIAM Journal on Computing, 1973, 2(1): 60-66.[IZ21] Iliashenko I, Zucca V. Faster homomorphic comparison operations …

《Flink学习笔记》——第八章 状态管理

8.1 Flink中的状态 8.1.1 概述 在Flink中,算子任务可以分为无状态和有状态两种情况。 **无状态的算子:**每个事件不依赖其它数据,自己处理完就输出,也不需要依赖中间结果。例如:打印操作,每个数据只需要…

(AS笔记)上传aar包到Maven中央仓库

目录 一、SonaType账户注册与登录 (1)注册 (2)登录 二、创建工单 (1)Github子域名验证 (2)自定义域名验证 三、登录Nexus Repository Manager 四、GPG签名生成和发布 五、Andr…

IEC 60068 环境测试介绍及其标准下载

IEC 60068 环境测试介绍及其标准下载 IEC 60068 标准由国际电工委员会 (IEC) 发布,是用于电工产品环境测试的国际标准。 IEC 60068 系列包含有关标准、环境测试程序和测试严重性的基本信息。 IEC 60068 环境测试 制定这一系列标准是为了在特定产品类型&#xff08…

C语言(第三十一天)

6. 调试举例1 求1!2!3!4!...10!的和&#xff0c;请看下面的代码&#xff1a; #include <stdio.h> //写一个代码求n的阶乘 int main() {int n 0;scanf("%d", &n);int i 1;int ret 1;for(i1; i<n; i){ret * i;}printf("%d\n", ret);return …

线性代数(五) 线性空间

前言 《线性代数(三) 线性方程组&向量空间》我通过解线性方程组的方式去理解线性空间。此章从另一个角度去理解 空间是什么 大家较熟悉的&#xff1a;平面直角坐标系是最常见的二维空间 空间由无穷多个坐标点组成 每个坐标点就是一个向量 反过来&#xff0c;也可说&…

【附安装包】CAD2024(建筑版)安装教程

软件下载 软件&#xff1a;CAD建筑版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;4.52G安装环境&#xff1a;Win11/Win10硬件要求&#xff1a;CPU2.5GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu.com/s/1cHe…

万级数据优化EasyExcel+mybatis流式查询导出封装

文章目录 前言.万级数据优化一. 直接上流式查询封装工具代码二. 传统分页导出查询三. 流式查询概念游标查询 前言.万级数据优化 我们不妨先给大家讲一个概念&#xff0c;利用此概念我们正好给大家介绍一个数据库优化的小技巧&#xff1a; 需求如下&#xff1a;将一个地市表的数…

CSS中如何实现文字阴影效果(text-shadow)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 实现思路⭐ 示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前…

视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查的相关问题及解决方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

解读GIS软件:从ArcGIS到山海鲸可视化的全方位介绍

在现代社会&#xff0c;地理信息系统&#xff08;GIS&#xff09;的应用已经渗透到了各个领域&#xff0c;为我们提供了丰富的地理数据分析和可视化工具。下面介绍几款常见的GIS工具软件&#xff0c;一起来了解它们的特点和优势。 1. ArcGIS: ArcGIS由Esri公司开发&#xff0c;…

php环境搭建步骤(与资源配套使用版)

1.将phpEnv.zip下载到D盘下 2.解压到当前文件夹 3.找到Apache24下的bin目录&#xff0c;执行cmd操作&#xff0c;回车。 4.在cmd中执行代码 Httpd -k install -n “Apache24” 4.使用winR键打开运行&#xff0c;输入services.msc &#xff0c;回车&#xff0c;进入服务 …

ipad有必要用手写笔吗?开学季实惠的电容笔推荐

iPad平板的机型经过了一次又一次的升级&#xff0c;增加了更多的功能&#xff0c;如今已有了与笔记本电脑匹敌的能力。而到了如今&#xff0c;科技的发展&#xff0c;iPad也从一个娱乐工具&#xff0c;变成了一个集学习、画画、办公于一体的强大工具。为了提高生产效率&#xf…