当前位置: 首页 > news >正文

HashMap的解析(1)

一、Hash的理解核心优势查找时间复杂度是O1本质原因HashMap 底层基于「数组」实现数组支持随机访问通过哈希函数直接定位到数组下标就能快速找到数据。无哈希冲突时就是O1有冲突时链表/红黑树会退化为OnOlog n底层数据结构key 数据的标识与操作入口value 要存储的数据本体hash key的哈希值定位与冲突处理的工具是计算得到的不是用户直接传进来的链表节点包含next指针红黑树节点包含parentleftright指针流程传入keyHashMap计算出来它的Hash值hash数组长度减一找到数组下标定位到对应的桶遍历桶中的数据结构找到对应节点最后返回这个节点对应的value数组长度为什么必须是2的幂1.如果数组长度是2的幂n-1的二进制全是1等价于去hash的低几位结果分布均匀冲突概率低2.如果不是这样则就会有零出现比如1110那么末尾一定会是0。3.扩容时无需重新计算hash可直接判断节点是否需要移动到新的位置提升扩容效率。只需要遍历对应的桶不需要将所有的部分全部再计算hash值。链表与红黑树的转换规则在单个桶长度大于8时链表会转换为红黑树长度小于6时红黑树转换为链表不是同一个树的原因防止这两个数反复横跳每次转换存储结构都会消耗资源。得到哈希冲突的两种情况纯正的Hash冲突两个不同的keyhashCode的返回值完全相同例如不同字符串的hash值重复。下标冲突伪冲突两个不同的keyhashCode值不同但与数组最大下标n-1做与运算后的数组下标相同二、代码初始练习根据大致功能进行的后期会完善先用取模代替与运算packageHash;//import java.util.HashMap;//K,V代表泛型意思时这个节点可以村任何类型的键和值。classNodeK,V{Kk;Vv;// 声明一个指针 next用来指向下一个 Node。这是拉链法解决冲突的关键它让节点能连成一条链表NodeK,Vnext;inthash;publicNode(Kk,Vv){this.kk;this.vv;this.hash(knull?0:k.hashCode());}}//定义自己的Hash类同样使用泛型k,VpublicclassHashK,V{//声明一个数组table里面存放的元素类型时NodeK,V,这是哈希桶privateNodeK,V[]table;//声明一个静态常量表示数组的默认初始长度必须是2的幂privatestaticfinalintDEFAULT_INITIAL_CAPACITY16;//声明一个静态常量表示负载因子当占有0.75的格子时说明该扩容了privatestaticfinalfloatDEFAULT_LOAD_FACTOR0.75f;//声明一个变量用来记录这个Map里到底存了多少个真实的键值对privateintelementSize;//声明一个变量记录table数组里有多少个格子被占用privateintarrUsedSize;//声明一个变量length用来记录当前数组的总长度16/32/64privateintlength;// Hash 类的构造方法当你 new Hash() 时会执行的代码publicHash(){// 初始化时把当前数组的长度设置为默认的 16lengthDEFAULT_INITIAL_CAPACITY;// 真正向内存申请空间创建一个长度为 16 的 Node 数组赋值给 table。此时里面全都是 nulltablenewNode[length];}// 核心的存入数据方法publicvoidput(Kk,Vv){// 1. 拿到 key 的哈希值inthash(knull)?0:k.hashCode();// 2. 计算下标用哈希值的绝对值对数组长度取模求余数// Math.abs() 是为了防止 hashCode 是负数导致数组越界报错intindexMath.abs(hash)%length;//运用取模来得到在哪个桶里// 3. 去对应的格子里看看原来有没有东西赋给 first 变量NodeK,Vfirsttable[index];// 情况1该位置是空的直接占用新格子if(firstnull){table[index]newNode(k,v);// 创建新节点直接扔进空格子elementSize;// 元素总数 1arrUsedSize;// 占用的格子数 1}// 情况2该位置已经有节点了发生哈希冲突else{// 先看第一个节点的 key 是不是我们要找的比较哈希值和 equals 内容//从前到后判断速度以此降低//先判断哈希值在判断两个对象内存你地址是否完全一样最后判断对象内的内容是否一致if(first.hashhashfirst.kk||first.k.equals(k)){first.vv;// key 完全相同说明你是来“修改”数据的更新 value}// 第一个节点不是你要的说明顺着它后面可能是一条链表顺着链表往下找else{NodeK,Vtempfirst;// 派出一个探路指针 temp从头开始找NodeK,Vnodenull;// 这是一个“标记兵”记录中途有没有找到同样的 key// 只要当前节点的后面还有节点就一直循环往下走while(temp.next!null){temptemp.next;// 指针往后挪一步// 检查挪到的这个节点是不是我们要找的 keyif(temp.hashhashtemp.kk||temp.k.equals(k)){temp.vv;// 找到了同样的 key更新 valuenodetemp;// 把这个节点记给标记兵说明不是新来的break;// 既然找到了就赶紧退出循环不用往下找了}}// 如果整个循环都找完了标记兵 node 还是 null说明这是一张全新的面孔if(nodenull){// 尾插法此时 temp 刚好停在链表的最末尾直接把新节点挂在它的 next 上temp.nextnewNode(k,v);elementSize;// 元素总数 1注意这里不加 arrUsedSize因为没占新格子}}}}//打印出来publicvoidprintMap(){System.out.println(当前状态);System.out.println(元素总数: elementSize, 占用格子数: arrUsedSize);// 遍历这 16 个格子for(inti0;itable.length;i){// 只打印那些装了东西的格子if(table[i]!null){System.out.print(格子 [i] - );NodeK,Vtemptable[i];// 如果格子里有链表就顺着链表一直打印到底while(temp!null){System.out.print({temp.ktemp.v} - );temptemp.next;}System.out.println(null/n);// 链表结尾指向 null}}}// 程序的启动入口main 方法publicstaticvoidmain(String[]args){// 1. 创建你的 Hash 实例HashString,StringmapnewHashString,String();// 2. 正常放入几个不同的 keymap.put(Apple,苹果);map.put(Banana,香蕉);map.put(Applee,苹果e);map.put(Appleee,苹果ee);// 3. 测试覆盖旧的值再次 put Applemap.put(Apple,超级大苹果);// 4. 查看打印结果验证底层结构map.printMap();}}
http://www.zskr.cn/news/1375388.html

相关文章:

  • Unity Android跨语言调用实战:NDK/JNI/C#内存与线程安全指南
  • 私有化部署Agent Harness:数据安全与可控性
  • 病房钢制门十大品牌有哪些?
  • 2026年智己LS8优势续航深度分析:家用SUV场景续航焦虑与操控痛点解析 - 品牌推荐
  • 状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
  • 基于CGCNN的晶体材料弹性模量预测:从图神经网络到高通量筛选实践
  • 基于贝叶斯优化与计算机视觉的量子点电荷态自动化搜索算法
  • 数据结构与算法之顺序表
  • ARM-FM:用大语言模型自动生成奖励机,破解强化学习稀疏奖励难题
  • 可解释机器学习解析心电信号:从特征工程到身份识别的核心特征挖掘
  • ARM SME指令集与MOVA指令详解:矩阵运算优化
  • 放射组学与机器学习在冠状动脉钙化自动评分中的实践与对比
  • C++正在向C语言发起“进攻”!TIOBE7月榜单发布
  • 基于K-d Tree与Keras的测光红移估计:解决训练样本偏差的机器学习实践
  • 26年5月系分论文~写作思路深度拆解
  • GameFramework资源管理实战:从Resource Editor配置到ProcedureLaunch初始化的完整代码解析
  • SSD健康预测:BiGRU-MHA混合模型技术解析
  • 脉冲神经网络在工业预测性维护中的低功耗应用
  • 保姆级教程:在Ubuntu 22.04上用GStreamer RTSP Server搭建多路摄像头监控推流服务
  • 告别鼠标点点点!Windows下用命令行玩转WebLogic服务启动与关闭(附完整路径与常见错误排查)
  • 面试官问我Redis,我背了八股文,他却问我“为什么缓存会雪崩”
  • Linux服务器挖矿攻击应急响应与实战清除指南
  • 企业级认证底座:RBAC权限模型与多租户OAuth实战架构
  • 别再手动传文件了!Unity 2022+ 用Plastic SCM实现多人协作的保姆级配置流程
  • 别再为Unity视频播放发愁了!Video Player从创建到避坑,保姆级教程带你搞定
  • 避坑指南:用Unity给PICO4打包APK时,SDK配置与场景管理的那些‘坑’
  • UE5 RPG实战:告别旧输入系统,用增强输入(Enhanced Input)优雅触发你的技能
  • 告别卡顿!用IL2CPP优化你的Unity游戏:性能提升与包体瘦身实测
  • Godot 4.2 2D游戏开发:用TileMap图层一键搞定游戏地图的可行走区域
  • 怎么挑公司文档管理软件?看懂这三点,老板不再为资料混乱抓狂