【数据结构】HashMap 和 HashSet

目录

1.哈希表概念

2冲突

2.1概念

2.2 冲突-避免

2.3冲突-避免-哈希函数设计

2.4 冲突-避免-负载因子调节

 ​编辑

2.5 冲突-解决-开散列/哈希桶

2.5冲突严重时的解决办法

3.实现

4.性能分析

5.与Java集合类的关系

 


1.哈希表概念

    在顺序结构中,元素关键码和存储位置并没有明确关系,因此在查找一个元素时,必须要经过多次比较,顺序结构中查找一个元素的时间复杂度是O(N),而在平衡树中,查找的时间复杂度是O(log2N),搜索的效率取决于元素的比较次数。

  那么有没有一种数据结构,可以做到查找的时间复杂度为O(1)呢?不经过任何比较,一次从表中直接得到要搜索的元素,通过某种函数使元素的存储位置和它的关键码建立一一映射的关系。那么在查找的时候就能够很快的通过该函数找到该元素。

当向该结构中:
  插入元素
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
  搜索元素
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。
该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash
Table)(或者称散列表)

例如:给出一组数据集合(1,7,6,4,5,9)

哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小

用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快
 

2冲突

2.1概念

对于两个数据元素的关键字Ki 和Kj (i != j),有Ki !=Kj ,但有:Hash(Ki ) == Hash(Kj),即:不同关键字通过相同哈
希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。
把具有不同关键码而具有相同哈希地址的数据元素称为“同义词“

2.2 冲突-避免


  首先,我们需要明确一点,由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率
 

2.3冲突-避免-哈希函数设计

    引起哈希冲突的一个原因可能是:哈希函数设计不够合理。 哈希函数设计原则:
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必在0到m-1之间
  哈希函数计算出来的地址能均匀分布在整个空间中
  哈希函数应该比较简单

常见哈希函数
1. 直接定制法--(常用)
取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B 优点:简单、均匀 缺点:需要事先知道关键字的分布情况 使用场景:适合查找比较小且连续的情况.
2. 除留余数法--(常用)
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址
 

2.4 冲突-避免-负载因子调节

 

负载因子和冲突率关系粗略演示:

所以当冲突率达到一个无法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。
已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小
 

2.5 冲突-解决-开散列/哈希桶


 

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

从上图可以看出,开散列中每个桶中放的都是发生哈希冲突的元素。
开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了
 

2.5冲突严重时的解决办法


刚才我们提到了,哈希桶其实可以看作将大集合的搜索问题转化为小集合的搜索问题了,那如果冲突严重,就意着小集合的搜索性能其实也时不佳的,这个时候我们就可以将这个所谓的小集合搜索问题继续进行转化,例如:
1. 每个桶的背后是另一个哈希表
2. 每个桶的背后是一棵搜索树

3.实现

我们先使用int来作为key和val的类型来简单实现一下hash

package demo1;public class HashBuck {//通过内部类来定义节点static class Node{private int key;private int val;private Node next;public Node(int key, int val) {this.key = key;this.val = val;}}public Node[] array; //数组public int useSize;//存放了多少个有效数据private final static float DEFAULT_LOAD_FACTOR = 0.75f; //额定负载因子public HashBuck() {this.array = new Node[10];}//初始化/*put方法,讲key和val存进去,如果负载因子超过了DEFAULT_LOAD_FACTOR (0.75)再调用resize方法进行扩容并重新哈希*/public void put(int key,int val){int index=key%array.length;Node cur = array[index];while (cur!=null){if(cur.key==key){cur.val=val;return;}cur=cur.next;}Node node=new Node(key,val);node.next=array[index];array[index]=node;useSize++;if(size()>DEFAULT_LOAD_FACTOR){resize();}}private final float size(){return  useSize*1.0f/array.length;}private void resize(){Node[] newarray =new  Node[array.length*2];for (int i = 0; i < array.length; i++) {Node cur = array[i];while (cur!=null){Node tmp=cur.next;int index = cur.key % newarray.length;cur.next=newarray[index];newarray[index] = cur;cur=tmp;}}array = newarray;}public int get(int key){int index=key%array.length;Node cur  =array[index];while (cur!=null){if(cur.key == key){return cur.val;}cur = cur.next;}return -1; //如果获取不到 则返回-1}}

4.性能分析

  虽然哈希表一直在和冲突做斗争,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的,也就是每个桶中的链表的长度是一个常数,所以,通常意义下,我们认为哈希表的插入/删除/查找时间复杂度是O(1)

5.与Java集合类的关系

1. HashMap 和 HashSet 即 java 中利用哈希表实现的 Map 和 Set
2. java 中使用的是哈希桶方式解决冲突的
3. java 会在冲突链表长度大于一定阈值后,将链表转变为搜索树(红黑树)
4. java 中计算哈希值实际上是调用的类的 hashCode 方法,进行 key 的相等性比较是调用 key 的 equals 方法。

所以如果要用自定义类作为 HashMap 的 key 或者 HashSet 的值,必须覆写 hashCode 和 equals 方法,而且要做到 equals 相等的对象,hashCode 一定是一致的
 



 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vue+eltable】修改表格滚动条样式

<style lang"scss" scoped> ::v-deep .el-table__body-wrapper::-webkit-scrollbar {width: 10px; /*纵向滚动条的宽度*/height: 10px; /*横向滚动条的高度*/ } /*定义滚动条轨道 内阴影圆角*/ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {bo…

Java 多线程之 volatile(可见性/重排序)

文章目录 一、概述二、使用方法三、测试程序3.1 验证可见性的示例3.2 验证指令重排序的示例 一、概述 在Java中&#xff0c;volatile 关键字用于修饰变量&#xff0c;其作用是确保多个线程之间对该变量的可见性和禁止指令重排序优化。 当一个变量被声明为volatile时&#xff0…

高德地图点击搜索触发输入提示

减少调用次数&#xff0c;不用每输入一次调用一次&#xff0c;输入完后再触发搜索 效果图&#xff1a; ![Alt](https://img-home.csdnimg.cn/images/20220524100510.png dom结构 <div class"seach"><van-searchshow-actionv-model"addressVal"…

【使用vscode在线web搭建开发环境--code-server搭建】

官方版本下载 https://github.com/coder/code-server/releases?q4.0.0&expandedtrue使用大于版本3.8.0,因为旧版本有插件市场不能访问的情况版本太高需要更新环境依赖 拉取安装包 []# wget "https://github.com/coder/code-server/releases/download/v4.0.0/code-…

探访九牧绿色黑灯工厂,找寻“科技卫浴 世界九牧”的答案

文 | 螳螂观察 作者 | 余一 你所想象中的工厂是怎么样的&#xff1f;灯火通明、人声鼎沸、人来人往&#xff1f;如果告诉你一座工厂既没有灯&#xff0c;也没有人&#xff0c;但却还在持续生产&#xff0c;你会不会觉得这是不可思议的事&#xff1f; 如果不是亲眼见证&#…

Simulink 自动代码生成:手写代码替换生成代码Code Replacement Tool使用

目录 前言 代码替换库操作步骤 代码生成验证 总结 前言 在实际工程开发过程中&#xff0c;Simulink生成的代码都是构建的算法实现的&#xff0c;纯软件实现&#xff0c;生成的代码大多也是直接在CPU上运行的。实际还有一些MCU集成了像Cordic&#xff0c;协处理器等。有些代…

WinEdt 11.1编辑器的尝鲜体验

WinEdt 11.1编辑器的尝鲜体验 2023年5月19日&#xff0c;WinEdt 11.1版本发布了&#xff0c;相比WinEdt 10.3, 最新版更加漂亮&#xff0c;更加友好&#xff0c;更加好用了&#xff01; 最大的改变是WinEdt 11.1 有了自带的WinEdtPDF阅读器&#xff0c;所以不再需要下载第三方…

ros2工作空间

我们先不管ros2工作空间是什么样子的&#xff0c;如果是我自己来搞一个工作空间&#xff0c;我一定是这样安排 一个文件夹用来放自己存放的文件&#xff0c;。。。。。。。。。。对应src文件夹 一个文件夹用来放编译后的文件&#xff0c;。。。。。。。。。。。对应intall文件…

2024测试工程师必学的Jmeter:利用jmeter插件收集性能测试结果汇总报告和聚合报告

利用jmeter插件收集性能测试结果 汇总报告&#xff08;Summary Report &#xff09; 用来收集性能测试过程中的请求以及事务各项指标。通过监听器--汇总报告 可以添加该元件。界面如下图所示 汇总报告界面介绍&#xff1a; 所有数据写入一个文件&#xff1a;保存测试结果到本地…

ZYNQ_project:LCD

模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a; /* // 24h000000 4324 9Mhz 480*272 // 24h800000 7084 33Mhz 800*480 // 24h008080 7016 50Mhz 1024*600 // 24h000080 4384 33Mhz 800*480 // 24h800080 1018 70Mhz 1280*800 */ module rd_id(i…

解决java在idea运行正常,但是打成jar包后中文乱码问题

目录 比如&#xff1a; 打包命令使用utf-8编码&#xff1a; 1.当在idea中编写的程序,运行一切正常.但是当被打成jar包时,执行的程序会中文乱码.产生问题的原因和解决方案是什么呢? 一.问题分析 分别使用idea和jar包形式打印出System中所有的jvm参数---代码如下: public static…

【设计模式】行为型设计模式

行为型设计模式 文章目录 行为型设计模式一、概述二、责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;三、命令模式&#xff08;Command Pattern&#xff09;四、解释器模式&#xff08;Interpreter Pattern&#xff09;五、迭代器模式&#xff08;Iterato…

Stable Diffusion专场公开课

从SD原理、本地部署到其二次开发 分享时间&#xff1a;11月25日14&#xff1a;00-17&#xff1a;00 分享大纲 从扩散模型DDPM起步理解SD背后原理 SD的本地部署:在自己电脑上快速搭建、快速出图如何基于SD快速做二次开发(以七月的AIGC模特生成系统为例) 分享人简介 July&#…

HelpLook VS Zendesk:哪种知识库软件更适合您的业务

为任何组织创造一个开放且协作的环境至关重要。然而&#xff0c;高水平的员工每周可能会花费多达30个小时处理电子邮件和协作&#xff0c;对他们的工作效率产生了重大影响。 为了解决这个挑战&#xff0c;建立一种高效的信息共享方法至关重要&#xff0c;不会妨碍团队的生产力…

福州大学《嵌入式系统综合设计》实验三:多媒体开发基础编程

一、实验目的 本实验基于搭建好的开发环境和硬件环境&#xff0c;通过编写简单的通信实验&#xff0c;验证开发环境&#xff0c;掌握多媒体开发编程基础&#xff0c;包括SOCKET编程、多线程编程和线程同步知识。 二、实验内容 基于套接字、多线程、同步锁机制实现多媒体文件…

循环链表3

插入函数——插入数据&#xff0c;在链表plsit的pos位置插入val数据元素 位置pos&#xff08;在无特别说明的情况下&#xff09;是从0开始计数的 要改变链表结构&#xff0c;就要依赖前驱&#xff0c;每个前驱的next存储着下一个数据结点的地址&#xff0c;也就是依靠前驱的ne…

netty整合websocket(完美教程)

websocket的介绍&#xff1a; WebSocket是一种在网络通信中的协议&#xff0c;它是独立于HTTP协议的。该协议基于TCP/IP协议&#xff0c;可以提供双向通讯并保有状态。这意味着客户端和服务器可以进行实时响应&#xff0c;并且这种响应是双向的。WebSocket协议端口通常是80&am…

FPGA——IP核 基础操作

FPGA——IP核 基础操作 IP核例化模块时钟IP核RAM IP核 IP核例化模块 找到模版 加入代码中 时钟IP核 配置模式功能 配置输入时钟 输出配置 RAM IP核

海外IP代理科普——API代理是什么?怎么用?

随着互联网的不断发展&#xff0c;越来越多的企业开始使用API&#xff08;应用程序接口&#xff09;来实现数据的共享和交流。而在API使用中&#xff0c;海外代理IP也逐渐普及。那么&#xff0c;什么是API代理IP呢&#xff1f;它有什么作用&#xff1f;API接口有何用处&#xf…

从0开始学习JavaScript--JavaScript 函数

JavaScript中的函数是编写可维护、模块化代码的关键。本文将深入研究JavaScript函数的各个方面&#xff0c;包括基本语法、函数作用域、闭包、高阶函数、箭头函数等&#xff0c;并通过丰富的示例代码来帮助读者更好地理解和应用这些概念。 函数的基本语法 函数是一段可被重复…