【数据结构】哈希表

目录

哈希表

基本思想

基本原理

哈希表工作机制简化描述

关于查找、插入和删除

HashMap

主要成员变量

主要方法

内部实现细节

注意事项


哈希表

哈希表是一种基于哈希函数的数据结构,它通过键值对的形式存储数据,并允许通过键快速查找对应的值。Java中的哈希表主要通过HashMap类来实现,它是java.util包的一部分。

基本思想

使用一个数组(table数组)来存放数据,但每个数组位置(也称为槽位或桶)不仅仅存放一个单独的值,而是可以存放一个数据结构来处理哈希冲突。这个数据结构最常见的是链表,但也可以是其他类型的数据结构,比如红黑树(在Java的HashMap中,当链表长度超过一定阈值时,会转换为红黑树以提高性能)

在接下来的学习中,我们会对这句话有更深的

基本原理

1.哈希函数

·哈希函数将键映射到哈希表中的索引位置(也称为桶或槽)

·理想情况下,哈希函数应尽可能均匀地分布键,以减少哈希冲突

注意:我们这里所说的映射并不是在Java中的反射

映射(Mapping)通常指的是将一种数据类型或对象关联到另一种数据类型或对象的过程。在哈希表中,映射特指将键(Key)通过哈希函数转换成一个索引为止,以便快速访问对应的值(Value)。

这种映射是静态的,即在编译时就已经确定了键和索引之间的对应关系(尽管实际的索引计算是在运行时进行的,但映射规则是编译时确定的)

反射(Reflection)

反射是Java语言的一种特性,它允许程序在运行时动态地获取类的信息、调用类的方法或修改类的属性。反射机制使得程序能够灵活地操作对象和类,而无需在编译时直到具体的类名或方法名。反射主要用于框架开发、动态代理、注解处理等场景

区别

·映射是对象之间的关联,通常用于数据结构之间的映射关系,如哈希表。而反射是对类本身进行操作,如获取类的信息、调用方法等

·映射是静态的,即映射规则在编译时确定。而反射是动态的,即可以在运行时获取和操作类的信息

·映射常用于数据处理和快速访问,而反射用于框架开发和实现灵活的功能

2.哈希冲突

·不同的键可能映射到相同的索引位置,这称为哈希冲突

·Java的HashMap使用链表或红黑树来处理冲突

哈希表工作机制简化描述

  1. 哈希函数:当我们想要插入一个元素时,首先使用一个哈希函数来计算该元素的哈希值。哈希函数将元素映射到数组的索引上
  2. 冲突处理:由于不同的元素可能会映射到数组的同一个索引(即哈希冲突),所以需要在每个数组位置存储一个能够处理这种冲突的数据结构。最常见的方法是链表法(也叫拉链法)和开放地址法

·链表法:每个数组位置存储一个链表,链表中的每个节点都存储一个元素。当发生哈希冲突时,新元素被添加到响应索引位置的链表的末尾

·开放地址法:当发生哈希冲突时,寻找数组中的下一个空位置来存储元素。这可以通过线性探测、二次探测或双重散列等方法实现

关于查找、插入和删除

·查找:使用哈希函数计算元素的哈希值,然后访问相应索引位置的链表(或其他数据结构),遍历链表直到找到目标元素或链表末尾

·插入:同样使用哈希函数找到索引位置,然后将新元素添加到相应索引位置的链表中

·删除:也是先找到索引位置,然后在链表中查找并删除目标元素

所以:哈希表使用一个数组table,每个位置可以存放一个能够处理哈希冲突的数据结构(最常见的是链表,但也可以是其他数据结构)

接下来我们这里通过简单讲解HashMap类,来了解如何使用哈希表及其内部方法

HashMap

主要成员变量

·transient Node<K,V>[] table :存储哈希表的数组,初始化为null,在第一次使用时懒加载并初始化为指定容量

·transient Set<Map.Entry<K,V>> entrySet:存储键值对的集合

·int size:当前存储的键值对数量

·int modCount:记录HashMap修改次数,用于快速失败机制

·int threshold:阈值,当哈希表中的键值对数量超过此值时,会进行扩容

·float loadFactor:加载因子(负载因子),用于确定何时扩容,默认为0.75f

主要方法

构造方法

1.HashMap()

2.HashMap(int initialcapacity)

3.HashMap(int initialcapacity,float loadFactor)

插入键值对

·put(K key,V value):将指定的键值对插入哈希表。如果键已存在,则更新其值

·putlfAbsent(K key,V value):如果指定的键尚未与某个值关联(或映射为null),则将其与给定值关联并返回null,否则返回当前值

获取值

·get(Object key):根据键获取值。如果键不存在,则返回null

·getOrDefault(Object key,V defaultValue):根据键获取值。如果键不存在,则返回指定的默认值。注意:如果指定的键为null,会抛出NullPointerException异常,因为HashMap不允许null键

·containsKey(Object key):检查哈希表中是否包含指定的键

·containsValue(Object value):检查哈希表中是否包含指定的值

删除键值对

·remove(Object key):根据键删除键值对。如果键存在,则返回其对应的值,否则返回null

遍历

·keySet() :返回包含所有键的集合

·values() :返回包含所有值的集合

·entrySet() :返回包含所有键值对的集合

其他

·size() :返回哈希表中的键值对数量

·isEmpty() :检查哈希表是否为空

·clear() :清空哈希表

代码案例

public static void main(String[] args) {//构建一个哈希表Map<String,Integer> hashmap=new HashMap<>();//插入键值对hashmap.put("apple",1);hashmap.put("banana",4);hashmap.put("orange",0);//获取值int a= hashmap.get("banana");System.out.println(a);//4System.out.println(hashmap.getOrDefault("orange",10));//0System.out.println(hashmap.getOrDefault("hhaa",100));//100System.out.println(hashmap.containsKey("apple"));//trueSystem.out.println(hashmap.containsValue(100));//falseSystem.out.println(hashmap.containsValue(1));//true//删除键值对hashmap.remove("apple");System.out.println(hashmap.containsKey("apple"));//false//遍历System.out.println(hashmap.keySet());//[banana, orange]System.out.println(hashmap.values());//[4, 0]System.out.println(hashmap.entrySet());//[banana=4, orange=0]}

内部实现细节

1.哈希计算

·HashMap使用key.hashCode方法计算键的哈希值,然后进一步处理以减少高位冲突

·indexFor(int h,int length)方法根据哈希值和数组长度计算索引位置

2.扩容

·当哈希表中的键值对数量超过阈值时,会进行自动扩容

·扩容后的数组容量是原来的两倍

·重新计算每个键的索引位置,并将键值对重新插入新的数组

3.链表转红黑树

·在Java 8中,当单个桶的链表长度超过8时,会转换为红黑树以提高查找效率

·当红黑树的大小 小于等于6时,会退化为链表

注意事项

·线程安全性:HashMap不是线程安全性。在多线程环境中,如果多个线程同时访问和修改HashMap,可能会导致数据不一致的问题。可以使用ConcurrentHashMap来替代

·null值:HashMap允许一个null值和多个null值

·性能:哈希表的性能取决于哈希函数的质量以及哈希表的负载因子和初始容量。选择合适的参数可以提高性能

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

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

相关文章

C++ Primer 初识泛型算法

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

解决后端跨域问题

目录 一、什么是跨域问题&#xff1f; 1、跨域问题的定义 2、举例 3、为什么会有跨域问题的存在&#xff1f; 二、解决跨域问题 1、新建配置类 2、编写代码 三、结语 一、什么是跨域问题&#xff1f; 1、跨域问题的定义 跨域问题&#xff08;Cross-Origin Resource Sh…

STM32MP157A-FSMP1A单片机移植Linux系统SPI总线驱动

SPI总线驱动整体上与I2C总线驱动类型&#xff0c;差别主要在设备树和数据传输上&#xff0c;由于SPI是由4根线实现主从机的通信&#xff0c;在设备树上配置时需要对SPI进行设置。 原理图可知&#xff0c;数码管使用的SPI4对应了单片机上的PE11-->SPI4-NSS,PE12-->SPI4-S…

springboot博客系统详解与实现(后端实现)

目录 前言&#xff1a; 项目介绍 一、项目的准备工作 1.1 数据准备 1.2 项目创建 1.3 前端页面的准备 1.4 配置配置文件 二、公共模块 2.1 根据需求完成公共层代码的编写 2.1.1 定义业务状态枚举 2.1.2 统一返回结果 2.1.3 定义项目异常 2.1.4 统一异常处理 三、业…

Metal 学习笔记四:顶点函数

到目前为止&#xff0c;您已经完成了 3D 模型和图形管道。现在&#xff0c;是时候看看 Metal 中两个可编程阶段中的第一个阶段&#xff0c;即顶点阶段&#xff0c;更具体地说&#xff0c;是顶点函数。 着色器函数 定义着色器函数时&#xff0c;可以为其指定一个属性。您将在本…

Kafka可视化工具EFAK(Kafka-eagle)安装部署

Kafka Eagle是什么&#xff1f; Kafka Eagle是一款用于监控和管理Apache Kafka的开源系统&#xff0c;它提供了完善的管理页面&#xff0c;例如Broker详情、性能指标趋势、Topic集合、消费者信息等。 源代码地址&#xff1a;https://github.com/smartloli/kafka-eagle 前置条件…

vue3.0将后端返回的word文件流转换为pdf并导出+html2pdf.js将页面导出为pdf

实现思路 1.将Word文档转换为HTML&#xff1a;mammoth.js&#xff0c;它可以将.docx文件转换为HTML 2.将HTML转换为PDF&#xff1a;使用html2pdf.js将HTML转换为PDF 如果想要相同的效果&#xff0c;也可以把前端页面直接导出转换为pdf: 运用的插件&#xff1a;html2pdf.js 后端…

lowagie(itext)老版本手绘PDF,包含页码、水印、图片、复选框、复杂行列合并等。

入口类&#xff1a;exportPdf ​ package xcsy.qms.webapi.service;import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.common.utils.StringUtils; import com.ibm.icu.text.RuleBasedNumberFormat; import com.lowa…

基于JAVA+SpringBoot+Vue的前后端分离的简历系统

基于JAVASpringBootVue的前后端分离的简历系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345…

AutoGen 技术博客系列 八:深入剖析 Swarm—— 智能体协作的新范式

本系列博文在掘金同步发布, 更多优质文章&#xff0c;请关注本人掘金账号&#xff1a; 人肉推土机的掘金账号 AutoGen系列一&#xff1a;基础介绍与入门教程 AutoGen系列二&#xff1a;深入自定义智能体 AutoGen系列三&#xff1a;内置智能体的应用与实战 AutoGen系列四&am…

可视化工具SciChart如何结合Deepseek快速创建一个React仪表板?

SciChart JavaScript Charts图表库能帮助用户来探索JS应用程序的最终解决方案&#xff0c;使用WebGL创建动态、高速的图表和图形&#xff0c;非常适合实时处理复杂的数据可视化&#xff0c;使用其强大而灵活的JS图表工具可以提升JavaScript项目。 通过在1000多个输出类型上使用…

Cesium@1.126.0,创建3D瓦片,修改样式

第一步&#xff1a;添加3D建筑 Cesium.createOsmBuildingsAsync()这是一个异步方法&#xff0c;所以要写在一个异步函数里 创建一个函数 const create3DBuilding async (viewer) > {try {// 添加3D建筑const tileset await Cesium.createOsmBuildingsAsync();viewer.scen…

二、大模型微调技术栈全解析

大模型微调技术栈全解析&#xff1a;从微调方法到算力支撑 在大模型的领域中&#xff0c;微调&#xff08;Fine-tuning&#xff09;就像是为模型量身定制的高级裁缝服务&#xff0c;能够让通用的大模型更好地适应特定的任务和场景。而要完成这项精细的工作&#xff0c;需要一整…

ARM Linux下FFmpeg+Nginx+RTMP 视频监控

一、流媒体协议 RTSP&#xff08;Real-Time Stream Protocol&#xff09;由 Real Networks 和 Netscape 共同提出的&#xff0c;基于文本的多媒体播放 控制协议。RTSP 定义流格式&#xff0c;流数据经由 RTP 传输&#xff1b;RTSP 实时效果非常好&#xff0c;适合视频聊天&…

图扑 HT for Web 总线式拓扑图的可视化实现

在图形用户界面&#xff08;GUI&#xff09;设计中&#xff0c;自定义连线技术不仅提升了用户体验&#xff0c;还为复杂数据可视化开辟了新的可能性。该功能点允许用户灵活地在界面元素之间创建视觉连接&#xff0c;使流程图、思维导图和网络拓扑图等信息呈现更加直观和动态。 …

大语言模型中的梯度值:深入理解与应用

1. 摘要 ​ 梯度是微积分中的一个基本概念&#xff0c;在机器学习和深度学习中扮演着至关重要的角色。特别是在大语言模型&#xff08;LLM&#xff09;的训练过程中&#xff0c;梯度指导着模型参数的优化方向。 本报告首先由浅入深地介绍梯度的概念&#xff0c;包括其数学定义…

Linux的用户管理

Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员申请一个账号&#xff0c;然后以这个账号的身份进入系统 root用户可以创建多个普通用户 一、添加用户 基本语法&#xff1a;useradd 用户名 当创建用户成…

C++第十七讲:map和set封装

C第十七讲&#xff1a;map和set封装 1.源码发现不同2.Mymap && Myset2.1红黑树的源码更改2.2迭代器的实现2.2.1源码的迭代器区别2.2.2const iterator的实现 2.3insert的实现2.4operator[]的理解 这一讲比较困难&#xff0c;我们首先会通过看map和set底层的源码&#xf…

Day9 25/2/22 SAT

【一周刷爆LeetCode&#xff0c;算法大神左神&#xff08;左程云&#xff09;耗时100天打造算法与数据结构基础到高级全家桶教程&#xff0c;直击BTAJ等一线大厂必问算法面试题真题详解&#xff08;马士兵&#xff09;】https://www.bilibili.com/video/BV13g41157hK?p4&v…

OpenCV的形态学操作

在计算机视觉中&#xff0c;形态学操作是一种基于集合论的图像处理技术&#xff0c;主要用于分析和处理图像的形状特征。OpenCV 提供了 cv2.morphologyEx() 函数&#xff0c;用于执行多种高级形态学操作。 kernel np.ones((15, 15), np.uint8) 1. 开运算&#xff08;Opening&…