Hash Table、HashMap、HashSet学习

news2024/9/21 0:31:36

文章目录

  • 前言
  • Hash Table(散列表)
    • 基本概念
    • 散列函数
    • 散列冲突(哈希碰撞)
    • 拉链法
      • 红黑树
      • 时间复杂度分析
  • HashMap
    • 基础
    • 方法使用
      • 基本的增删改查
      • 其他的方法
    • 实现原理
  • HashSet
    • 基础操作
    • 去重原理

前言

本文用于介绍关于Hash Table、HashMap、HashSet的学习。
本文中有的地方说的是哈希,有的地方说的是散列,只需记住,在本文中哈希就是散列,散列就是哈希。

Hash Table(散列表)

散列表也就是哈希表,在散列表中使用到了红黑树和链表(下面会介绍),无论是HashMap还是HashSet,它们都是基于散列表实现的,所以先简单介绍一下散列表。

基本概念

散列表是根据键key直接访问值value的数据结构,它是由数组演化而来,利用了数组支持按下标进行随机访问数据的特性。

在数组中,索引下标就可以作为key,数组中的元素就可以作为value,我们可以通过下标索引(key)直接获取到数组中的元素(value)。

散列函数

散列表的key可以是各种各样的数据结构,而数组下标是整数,所以将各种各样数据结构的key映射为数组下标的函数就叫散列函数(哈希函数)。可以表示为hashValue=hash(key)

散列函数的基本要求

  • 散列函数计算得到的散列值必须是大于等于0的正整数,因为hashValue需要作为数组的下标
  • 如果key1==key2,那么经过散列函数计算出的hashValue一定相等,即hash(key1)==hash(key2)
  • 如果key1!=key2,那么经过散列函数计算出的hashValue一定不相等,即hash(key1)!=hash(key2)(几乎不可能)

散列冲突(哈希碰撞)

实际上想找到一个散列函数能做到不同的key计算出的hashValue值不同是几乎不可能的,这就是散列冲突,也就是指多个key的hashValue相等,映射到了同一个数组下标

拉链法

拉链法是解决哈希冲突的方法。在散列表中,数组的每个下标位置我们可以称为或者,每个桶(槽)会对应一条链表,所有散列值(hashValue)相同的元素我们会放到相同槽位对应的链表中,如下。

在这里插入图片描述

红黑树

拉链法的使用的链表我们可以改造为效率更高的红黑树,这里简单介绍一下红黑树。

红黑树:是一种自平衡的二叉搜索树(二叉搜索树:对于树中的任意一个节点,左子树节点的值都小于该节点的值,右子树节点的值都大于该节点的值),红黑树与二叉搜索树不同的就是有一个平衡机制,可以避免二叉搜索树的最差情况(链表)。

在这里插入图片描述

红黑树的特性:

  • 节点要么是红色,要么是黑色
  • 根节点是黑色
  • 叶子节点都是黑色的空节点
  • 红黑树中的红色节点的子节点是黑色的
  • 从任一节点到叶子节点的所有路径都包含相同数目的黑色节点

在添加或删除节点的时候,如果不符合这些性质会发生旋转,以达到所有性质,完成性质的目标就是为了保证平衡

红黑树的时间复杂度

  • 查找:红黑树也是二叉搜索树,所以查找的时间复杂度为O(logn)
  • 添加:从根节点开始找到元素添加的位置,时间复杂度为O(logn),添加完成后涉及到时间复杂度为O(1)的旋转操作,所以整体时间复杂度为O(logn)
  • 删除:从根节点开始找到元素删除的位置,时间复杂度为O(logn),删除完成后涉及到时间复杂度为O(1)的旋转操作,所以整体时间复杂度为O(logn)

时间复杂度分析

  • 插入元素:只需通过散列函数计算出相应的槽位,插入槽位对应的链表的末尾即可,时间复杂度为O(1)
  • 查找和删除元素:也是先通过哈希函数计算出相应的槽位,再遍历槽位对应的链表进行插入和删除
    • 在平均情况下(元素分布比较平均)基于链表法解决哈希散列冲突的时间复杂度是O(1)
    • 散列表可能退化为链表(所有元素通过散列函数计算出的槽位都是同一个槽位),查询时间复杂度就变为了O(n)
    • 可以将链表法中的链表改为其他更高效的数据结构,如红黑树(如下图),时间复杂度为O(logn)

在这里插入图片描述

将链表法中的链表改为红黑树还有一个好处:可以防止DDos攻击(分布式拒绝服务攻击,指处于不同位置的多个攻击者对一个或多个目标进行攻击,或者一个攻击者控制位于不同位置的多个机器对目标同时实施攻击),DDos攻击可以伪装大量的key插入链表中,这样我们如果是使用的链表的话访问时效率就会非常低。

HashMap

基础

HashMap是Java中一个非常重要的数据结构,用于存储键值对(key-value)信息。它基于哈希表实现,提供了时间复杂度为O(1)的查找、插入和删除操作,所以从算法层面来说,我们常使用HashMap来判断一个元素是否在集合中。

HashMap具有以下特性:

  • 键值对存储:存储的是键值对,每个键(key)都有一个值(value)
  • 键的唯一性:在HashMap中,键是唯一的,如果先后插入两个键相同的值时,后插入的值会将前面一个值覆盖
  • 无序:不保证元素的顺序,元素的顺序可能会随着插入和删除操作而变化
  • 线程不安全:HashMap是线程不安全的,在多线程环境下,如果多个线程同时访问和修改HashMap,可能造成数据不一致的情况。

方法使用

要使用HashMap,我们需要先对其进行定义:

//键为整数类型,值为字符串类型
HashMap<Integer,String> hashMap=new HashMap<Integer,String>();

基本的增删改查

  • 增加数据
//添加键的同时添加值
hashMap.put(1,"aaa");
hashMap.put(2,"bbb");
hashMap.put(3,"ccc");
  • 删除数据
//根据键删除值
hashMap.remove(1);

//清空所有数据
hashMap.clear();
  • 修改数据
//根据键修改数据
hashMap.replace(2,"bbbb");
  • 查询数据
//根据键查询数据
hashMap.get(2);

除此之外还存在一个getOrDefault()方法:

hashMap.getOrDefault(2,defaultValue);

这个方法用于查询是否存在这个key对应的value,如果没有,返回defaultValue。

String defaultValue=hashMap.getOrDefault(4,"ddd");
System.out.println(defaultValue);//由于并未添加键为4,值为ddd的数据,所以输出ddd

其他的方法

  • HashMap是否为空
hashMap.isEmpty();
  • 获取HashMap中键值对的数量
int size=hashMap.size();
  • 是否存在某个键值对
hashMap.containsKey(1);//是否存在键为1的键值对
hashMap.containsValue("aaa");//是否存在值为"aaa"的键值对
  • 分别返回所有键和值
Set<Integer> list1=hashMap.keySet();//所有键的集合
Collection<String> list2=hashMap.values();//所有值的集合

实现原理

HashMap的数据结构:底层使用散列表(哈希表)数据结构,即数组+链表或数组+红黑树

  • 当我们使用put方法向HashMap中添加元素时,会利用key的hashCode计算出hashValue(哈希值),对应两种结果

    • hashValue相同,key也相同:覆盖原始值
    • hashValue相同,key不相同:将当前的key-value存入链表或红黑树中
  • 使用get方法获取数据时,先找到hashValue对应的下标(桶或槽),再进一步通过key找到value

需要注意的是:

  • 在jdk1.8之前:拉链法只有将数组和链表结合,遇到哈希冲突就将冲突的值添加到链表中
  • 在jdk1.8之后:当链表长度大于阈值(默认为8)并且数组长度达到64时,就会将链表转为红黑树,这样做可以减少搜索时间还能防止DDos

HashSet

HashSet是一个不允许有重复元素的集合,但允许存在null值。

特性:

  • 不允许重复:不允许存储重复的元素,使用add方法存储重复的元素时会返回false
  • 无序:内部元素的存储是无序的,就算添加元素时是有序的,HashSet也不保证遍历时的顺序与添加时的一致
  • 高效:添加、删除、查找的时间复杂度都为O(1)

基础操作

  • 定义一个HashSet
Set<Integer> set=new HashSet<Integer>();
  • 添加值
set.add(100);
  • 删除元素
set.remove(100);
//移除所有元素
set.clear();
  • 判断元素是否存在
set.contains(100);

去重原理

HashSet通过hashCode()(用于计算出hashValue)和equals()(比较对象的地址值是否相同)方法实现去重。

在向HashSet添加元素时:会先调用hashCode()方法来计算出hashValue来判断对象加入的位置,如果该位置没有值,则直接插入;如果发现该位置存在值,则会调用equals()方法来判断两个对象是否相同(对象不同就是哈希冲突,上面有介绍),如果相同则添加失败返回false。

学习分享到此结束,希望能对你有所帮助!

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

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

相关文章

UnLua调用C++函数

一、UnLua调用C全局静态函数 1、新建C类MyLuaUtils&#xff0c;继承BlueprintFunctionLibrary,实现全局静态函数GetInt。 MyLuaUtils.h UCLASS() class LUASHOOTING_API UMyLuaUtils : public UBlueprintFunctionLibrary {GENERATED_BODY()UFUNCTION(BlueprintCallable)static…

leetcode hot100_part17_技巧篇

题目 136.只出现一次的数字 结合题目给的数据特征&#xff0c;使用位运算中的异或^&#xff1b;异或的结果很好记&#xff0c;相互不同就是1&#xff0c;相同就是0&#xff1b;同或一样的 169.多数元素 直接排序了 后面那几个方法不看了&#xff0c;追求效率可以再看&#…

前端工程化详解 包管理工具

前端工程化详解 & 包管理工具 1、工程化体系介绍1.1、 什么是前端工程化1.2、 前端工程化发展 2、脚手架能力2.1 准备阶段2.2 开发阶段2.3 发布流程 3、npm能力3.1 剖析package.json3.1.1 必备属性3.1.2 描述信息3.1.3 依赖配置3.1.4 协议3.1.5 目录&文件相关3.1.5.1 程…

MATLAB基础语法知识

环境的配置等等就不写了&#xff0c;网上还是有很多资源可以找&#xff0c;而且正版的要付费&#xff0c;我也是看的网上的搞定的。 一&#xff0c;初识MATLAB 1.1 MATLAB的优势 不需要过多了解各种数值计算方法的具体细节和计算公式&#xff0c;也不需要繁琐的底层编程。可…

Untiy TTF转换为SDF

Untiy TTF转换为SDF 原因 下载的字体是TTF格式&#xff0c;但是TMP使用的是SDF格式&#xff0c;不支持TTF&#xff0c;需要转换网络没有检索到TTF转SDF的教程&#xff0c;可能是太简单了&#xff0c;自己记录一下吧 Unity内转换即可 在Asset中找到自己的TTF右键点击TTF&…

C++入门基础篇

引言 说到编程语言常常听到的就是C语言C Java 。C语言是面向过程的&#xff0c;C是和Java是面向对象的&#xff0c;那么什么是面向对象呢&#xff1f;什么又是面向过程呢&#xff1f;C是什么&#xff1f;封装、继承、多态是什么&#xff1f;且听我絮絮叨叨。 C入门基础 1.命名…

fluent 旋转机械流场与声场仿真-学习笔记

这里写目录标题 1、动网格与滑移网格、运动参考系2、网格拓扑与共节点设置3、模型选择4、关于旋转壁面&#xff08;rotor_blade)的边界条件设置5、滑移网格瞬态计算时间步长设置6、风机声场仿真域![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7855a595ee704c42a644…

【linux学习指南】Linux项目自动化构建工具 make /makefile进度条代码

文章目录 &#x1f4dd;前言&#x1f320; Makefile 格式&#x1f309;Makefile命令符号 &#x1f320;makefile/make基本原理&#x1f309;总和小案例 &#x1f320;进度条代码&#x1f6a9;总结 &#x1f4dd;前言 一个工程中的源文件多不技计数&#xff0c;其按其按类型、功…

某部门系统主机中病毒分析

一、安全巡检 正在写着代码&#xff0c;我的电脑火绒软件提示有内网攻击&#xff0c;关于一个古老的漏洞&#xff1a;“永恒之蓝”。瞬间来了兴趣&#xff0c;不会现在仍然有电脑中这病毒吧&#xff0c;打开绿盟安全管理平台。根据IP查询记录&#xff0c;果然有很多漏洞。 发…

《深入浅出WPF》读书笔记.11Template机制(上)

《深入浅出WPF》读书笔记.11Template机制(上) 背景 模板机制用于实现控件数据算法的内容与外观的解耦。 《深入浅出WPF》读书笔记.11Template机制(上) 模板机制 模板分类 数据外衣DataTemplate 常用场景 事件驱动和数据驱动的区别 示例代码 使用DataTemplate实现数据样式…

2024Mysql And Redis基础与进阶操作系列(1)作者——LJS[含MySQL的下载、安装、配置详解步骤及报错对应解决方法]

目录 1.数据库与数据库管理系统 1.1 数据库的相关概念 1.2 数据库与数据库管理系统的关系 1.3 常见的数据库简介 Oracle 1. 核心功能 2. 架构和组件 3. 数据存储和管理 4. 高可用性和性能优化 5. 安全性 6. 版本和产品 7. 工具和接口 SQL Server 1. 核心功能 2. 架构和组…

唯徳知识产权产权系统存在任意文件读取漏洞

漏洞描述 深圳市唯德科创信息有限公司&#xff08;以下简称&#xff1a;唯德&#xff09;于2014年在深圳成立&#xff0c;是专业提供企业、代理机构知识产权管理软件供应商&#xff0c;唯德凭借领先的技术实力和深厚的专利行业积累&#xff0c;产品自上市推广以来&#xff0c;…

一文讲懂Spring Event事件通知机制

目录 一 什么是spring event 二 怎么实现spring event 一 什么是spring event 我不会按照官方的解释来说什么是spring event&#xff0c;我只是按照自己的理解来解释&#xff0c;可能原理上会和官方有偏差&#xff0c;但是它的作用和功能就是这个&#xff0c;我更加偏向于从他…

CTK框架(三): 插件的安装

目录 1.方式1&#xff1a;使用ctk框架工厂&#xff0c;适用于调用普通的插件 1.1.步骤 1.2.实现 2.方法2&#xff1a;使用ctk框架启动器&#xff0c;适用于需要eventadmin时 2.1.实现 3.注意事项 1.方式1&#xff1a;使用ctk框架工厂&#xff0c;适用于调用普通的插件 1…

Linux服务器应急响应(下)

目录 介绍步骤 介绍 Linux alias命令用于设置指令的别名。 用户可利用alias&#xff0c;自定指令的别名。若仅输入alias&#xff0c;则可列出目前所有的别名设置。alias的效力仅及于该次登入的操作。若要每次登入是即自动设好别名&#xff0c;可在.profile或.cshrc中设定指令…

ggplot2 缩小的、带箭头的坐标轴 | R语言

1. 效果图 左侧为DimPlot2()效果图。 右侧为DimPlot()效果图&#xff0c;原图。 2. 代码 # DimPlot with 缩小的坐标轴 # # param scObject # param reduction # param group.by # param label # param raster # param legend.position # param ... # # return # expo…

OCC开发_变高箱梁全桥建模

概述 上一篇文章《OCC开发_箱梁梁体建模》中详细介绍了箱梁梁体建模的过程。但是&#xff0c;对于实际桥梁&#xff0c;截面可能存在高度、腹板厚度、顶底板厚度变化&#xff0c;全桥的结构中心线存在平曲线和竖曲线。针对实际情况&#xff0c;通过一个截面拉伸来实现全桥建模显…

长短期记忆神经网络-LSTM回归预测-MATLAB代码实现

一、LSTM简介&#xff08;代码获取&#xff1a;底部公众号&#xff09; 长短期记忆神经网络&#xff08;Long Short-Term Memory, LSTM&#xff09;是一种循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;的变体。相比于传统的RNN&#xff0c;LSTM能够更好…

nvidia-smi 随机掉卡,error,禁用GSP功能

问题 NVIDIA 驱动中默认开启加载GPU卡的GSP功能&#xff0c;会随机导致在执行nvidia-smi命令的时候读取GPU卡为ERR状态&#xff0c;或者导致smi命令卡死&#xff1b; 如下图&#xff0c;以A800为例&#xff0c;Centos系统&#xff1b; 涉及到的包含以下型号的GPU卡&#xff…

C#中chart绘制曲线

官网资料&#xff1a;Chart 类 (System.Windows.Forms.DataVisualization.Charting) | Microsoft Learn 类的 Chart 两个重要属性是 Series 和 ChartAreas 属性&#xff0c;这两个属性都是集合属性。 Series集合属性存储Series对象&#xff0c;这些对象用于存储要显示的数据以…