首页 > 其他分享 >散列表

散列表

时间:2024-03-06 20:45:19浏览次数:17  
标签:HashMap 哈希 列表 链表 数组 Entry

散列表

   概要

   散列表也叫哈希表(hash table),是存储Key-Value映射的集合。对于某一个Key,散列表可以在接近O(1)的时间内进行读写操作。

   散列表通过哈希函数实现Key和数组下标的转换,每个键值对都会通过哈希函数计算出一个索引,然后存储在对应的位置上。通过开放寻址法和链表法来解决哈希冲突 。

   散列表在本质上也是一个数组,可以根据下标,进行元素的随机访问。

   一、Java中的hashMap

   HashMap 是 Java 中的一种数据结构,用于存储键值对。它实际上是基于散列表(hash table)实现的。

   HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。 

   HashMap数组每一个元素的初始值都是Null。

   1. 写操作(Put)方法的原理

   写操作就是在散列表中插入新的键值对(在JDK中叫做Entry)

   1)   通过哈希函数来确定Entry的插入位置(index)

   2)如果该位置没有元素,就把这个Entry填充进去,但是,由于数组的长度是有限的,当插入的Entry越来越多时,不同的key通过哈希函数获得的下标可能是相同的。这种情况就叫做哈希冲突。

  解决哈希冲突的方法主要有两种:开放寻址法和链表法。在Java中,针对解决哈希冲突,ThreadLocal所使用的就是开放寻址法,HashMap中采用的链表法。

  链表法:HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可,采用头插法(HashMap的发明者认为,后插入的Entry被查找的可能性更大。)

   2. 读操作(Get)方法的原理
   1) 通过哈希函数,把key转化为对应的index

   2) 通过index找到对应的元素,由于刚才所说的Hash冲突,同一个位置有可能匹配到多个Entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。

   3. 扩容(Resize)的原理
  既然散列表是基于数组实现的,那么散列表也要涉及扩容的问题

当经过多次元素插入,散列表达到一定饱和度时,key映射位置发生冲突的概率会逐渐提高。这样一来,大量元素拥挤在相同的数组下标位置,形成很长的链表,对后续插入操作和查询操作的性能都有很大影响。

   1)影响扩容的两个因素
   Capacity:HashMap的当前长度
   LoadFactor:HashMap的负载因子,默认值为0.75f

   2)衡量HashMap需要进行扩容条件
   HashMap.size >= Capacity * LoadFactor

   3)扩容步骤
   扩容:创建一个新的Entry空数组,长度是原数组的2倍
   重新Hash:遍历原Entry数组,把所有的Entry重新Hash到新数组中。
   经过扩容,原本拥挤的散列表重新变得稀疏,原有的Entry也重新得到了尽可能均匀的分配

   4.  HashMap默认的初始长度

   1)  初始长度
   HashMap的默认初始长度是16,并且每次自动扩展或者手动初始化时,长度必须是2的幂

   原因:之所以选择16,是为了服务于从Key映射到index的hash算法。长度16或者其他2的幂,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。

   说明:如果长度为其他情况,那么有些index结果的出现几率会更大,而有些index结果永远不会出现。不符合Hash算法均匀分布的原则。

   2)哈希函数

   从Key映射到HashMap数组的对应位置,会用到一个Hash函数:

   index = HashCode(Key) & (Length - 1)

   说明:取模运算的方式固然简单,但是效率很低。为了实现高效的Hash算法,HashMap的发明者采用了位运算的方式。

 

   5. 高并发下,为什么HashMap可能会出现死锁


   6. Java8中,HashMap的结构有什么样的优化?

标签:HashMap,哈希,列表,链表,数组,Entry
From: https://www.cnblogs.com/hld123/p/18057498

相关文章

  • Python list列表pop弹出内容del移除内容结果不对错误
    前言全局说明Pythonlist列表pop弹出内容del移除内容结果不对一、功能需求一个list列表,内容是1-9,用for循环打印,打印过的值,从列表中删除二、输出结果不对,代码有问题文件名:test.py#!/usr/bin/envpython3#coding:UTF-8#-*-coding:UTF-8-*-lists_1=['a','b']......
  • ems-jsp 职工列表功能
    1.思路简单的一个数据库查询所有,将数据放入list列表,通过spring提供的model传入到前端页面。2.代码controller:/**员工列表**/@RequestMapping("list")publicStringlistEmployee(HttpServletRequestrequest,Modelmodel){List<Employ......
  • Axure中继器高阶玩法-列表的增删改查
    1.效果展示2.实现步骤设计原理:新增修改时,对新增或标记的内容,插入中继器中,列表再展示中继器内的内容2.1.前提步骤●页面及样式设计,如下。建立查询条件、查询框、按钮、新增/修改/删除弹窗(最好是用一个动态面板完成,这样弹窗位置固定且页面展示有条理不会显得臃肿)、列表名、列表......
  • 使用 Java 在Excel中创建下拉列表
    下拉列表(下拉框)可以确保用户仅从预先给定的选项中进行选择,这样不仅能减少数据输入错误,还能节省时间提高效率。在MSExcel中,我们可以通过“数据验证”提供的选项来创建下拉列表,但如果要在Java程序中通过代码实现这一功能,可能需要借助一些第三方库。本文将分享两种使用免费Java库......
  • 列表推导式
    推导式推导式是通过一行循环判断遍历出一些列数据的方法。语法:valforvaliniterable#创建一个包含1到50的列表:lst=[iforiinrange(1,51)]print(lst)带有运算操作的推导式创建一个列表,其中每个元素都是原始列表中对应元素的两倍:lst=[i*2foriinrange(1,6)......
  • python列表、集合、字典转换要点以及查找速度区别,如何在大规模数据中实现快速查找
    1.list与set的区别与优缺点:循环速度:list最适合做固定长度的遍历,而且有顺序。set是无序的,list转换为set会乱序,若用set给list去重,转化为list时须用原list的index排序:new_list.sort(key=old_list.index)。所以这种循环尽量用list查询速度:set>list,set查询的key都是ha......
  • 第三章 列表与元组
    第3章列表与元组一、列表1、创建:x=list()#创建,delx#删除,2、转换:x=list('Python')3、常用方法:方法功能举例append(object,/)追加object到尾部clear()删除所有元素copy()复制所有元素count(value,/)计算value出现的次数extend(iterable)......
  • Tiktok api接口 获取视频列表、用户详情,视频无水印数据采集
    iDataRiver平台https://www.idatariver.com/zh-cn/提供开箱即用的Tiktok数据采集API,供用户按需调用。接口使用详情请参考Tiktok接口文档接口列表1.获取用户详情参数类型是否必填默认值示例值描述apikeystring是idr_***从控制台里复制apikeyuser_idnu......
  • nginx建立视频播放列表
    本地需要测试播放器,遂需要建立一个视频服务先将视频放到此地然后更改nginx.confserver{listen80;server_namelocalhost;#将m3u8文件夹映射到根目录下location/{roothtml/movies;autoin......
  • 【C++】Mat和Pat希望邀请他们的朋友来参加派对。他们要编写一个程序完成下面的任务。
    Mat和Pat希望邀请他们的朋友来参加派对。他们要编写一个程序完成下面的任务。让Mat输入他朋友的姓名列表。姓名存储在一个容器中,然后按排列后的顺序显示出来。让Pat输入她朋友的姓名列表。姓名存储在另一个容器中,然后按排列后的顺序显示出来。创建第三个容器,将两个列表合并,删除重......