线性数据结构-手写队列-哈希(散列)Hash

什么是hash散列?
哈希表的存在是为了解决能通过O(1)时间复杂度直接索引到指定元素。这是什么意思呢?通过我们使用数组存放元素,都是按照顺序存放的,当需要获取某个元素的时候,则需要对数组进行遍历,获取到指定的值。而这样通过循环遍历比对获取指定元素的操作,时间复杂度是O(n),也就是说如果你的业务逻辑实现中存在这样的代码是非常拉胯的。那怎么办呢?这就引入了哈希散列表的设计。
在这里插入图片描述
也就是说我们通过对一个 Key 值计算它的哈希并与长度为2的n次幂的数组减一做与运算,计算出槽位对应的索引,将数据存放到索引下。那么这样就解决了当获取指定数据时,只需要根据存放时计算索引ID的方式再计算一次,就可以把槽位上对应的数据获取处理,以此达到时间复杂度为O(1)的情况
在这里插入图片描述
哈希散列虽然解决了获取元素的时间复杂度问题,但大多数时候这只是理想情况。因为随着元素的增多,很可能发生哈希冲突,或者哈希值波动不大导致索引计算相同,也就是一个索引位置出现多个元素情况。如图所示;
在这里插入图片描述
就出现了一系列解决方案,包括;HashMap 中的拉链寻址 + 红黑树、扰动函数、负载因子、ThreadLocal 的开放寻址、合并散列、杜鹃散列、跳房子哈希、罗宾汉哈希等各类数据结构设计。让元素在发生哈希冲突时,也可以存放到新的槽位,并尽可能保证索引的时间复杂度小于O(n)。
以下为实战部分
1:哈希碰撞
在这里插入图片描述
测试上述简单的map结构。
在这里插入图片描述
通过测试结果可以看到,碰撞前 map.get(“01”) 的值是花花,两次下标索引碰撞后存放的值则是苗苗
这也就是使用哈希散列必须解决的一个问题,无论是在已知元素数量的情况下,通过扩容数组长度解决,还是把碰撞的元素通过链表存放,都是可以的。
2:拉链寻址
既然我们没法控制元素不碰撞,但我们可以对碰撞后的元素进行管理。比如像 HashMap 中拉链法一样,把碰撞的元素存放到链表上。
在这里插入图片描述
测试拉链寻址
在这里插入图片描述
3:开放寻址
除了对哈希桶上碰撞的索引元素进行拉链存放,还有不引入新的额外的数据结构,只是在哈希桶上存放碰撞元素的方式。它叫开放寻址,也就是 ThreaLocal 中运用斐波那契散列+开放寻址的处理方式。
在这里插入图片描述
开放寻址的设计会对碰撞的元素,寻找哈希桶上新的位置,这个位置从当前碰撞位置开始向后寻找,直到找到空的位置存放。
在 ThreadLocal 的实现中会使用斐波那契散列、索引计算累加、启发式清理、探测式清理等操作,以保证尽可能少的碰撞。
在这里插入图片描述
4:罗宾汉哈希
罗宾汉哈希是一种基于开放寻址的冲突解决算法;冲突是通过偏向从其“原始位置”(即项目被散列到的存储桶)最远或最长探测序列长度(PSL)的元素的位移来解决的。

public void put(K key, V value) {Entry entry = new Entry(key, value);int idx = hash(key);System.out.println(key + " " + idx);// 元素碰撞检测while (table[idx] != null) {if (entry.offset > table[idx].offset) {// 当前偏移量不止一个,则查看条目交换位置,entry 是正在查看的条目,增加现在搜索的事物的偏移量和 idxEntry garbage = table[idx];table[idx] = entry;entry = garbage;idx = increment(idx);entry.offset++;} else if (entry.offset == table[idx].offset) {// 当前偏移量与正在查看的检查键是否相同,如果是则它们交换值,如果不是,则增加 idx 和偏移量并继续if (table[idx].key.equals(key)) {// 发现相同值V oldVal = table[idx].value;table[idx].value = value;} else {idx = increment(idx);entry.offset++;}} else {// 当前偏移量小于我们正在查看的我们增加 idx 和偏移量并继续idx = increment(idx);entry.offset++;}}// 已经到达了 null 所在的 idx,将新/移动的放在这里table[idx] = entry;size++;// 超过负载因子扩容if (size >= loadFactor * table.length) {rehash(table.length * 2);}}@Overridepublic V get(K key) {int offset = 0;int idx = hash(key);while (table[idx] != null) {if (offset > table[idx].offset) {return null;} else if (offset == table[idx].offset) {if (table[idx].key.equals(key)) {return table[idx].value;} else {offset++;idx = increment(idx);}} else {offset++;idx = increment(idx);}}return null;}

通过测试结果和调试的时候可以看到,哈希索引冲突是通过偏向从其“原始位置”(即项目被散列到的存储桶)最远或最长探测序列长度(PSL)的元素的位移来解决。
最后附上经典面试题。
介绍一下散列表?
为什么使用散列表?
拉链寻址和开放寻址的区别?
还有其他什么方式可以解决散列哈希索引冲突?
对应的Java源码中,对于哈希索引冲突提供了什么样的解决方案?
友友们在评论区写下你们的答案!
以上的是线性数据结构-手写队列-哈希(散列)Hash 若需完整代码 可识别二维码后 给您发代码。
在这里插入图片描述

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

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

相关文章

ton-http-api安装部署

1、拉取github代码 mkdir /data git clone https://github.com/toncenter/ton-http-api.git cd ton-http-api2、创建环境变量 ./configure.py cat .env TON_API_CACHE_ENABLED0 TON_API_CACHE_REDIS_ENDPOINTcache_redis TON_API_CACHE_REDIS_PORT6379 TON_API_CACHE_REDIS_T…

6.k8s中的secrets资源

一、Secret secrets资源,类似于configmap资源,只是secrets资源是用来传递重要的信息的; secret资源就是将value的值使用base64编译后传输,当pod引用secret后,k8s会自动将其base64的编码,反编译回正常的字符…

仿知乎网站问答源码,开源版

仿知乎网站问答源码,开源版 需要一定动手能力 发文章,发视频,发想法,提问回答,注册登录 开发环境 使用技术:springbootthymeleafRedis; 开发环境:tomcat8.0,jdk8.0, ID…

2023下半年软件设计师上午题——冒泡排序

快速排除法,根据冒泡排序特性,每一趟排序都会确实最大/最小值,故升序两趟后,最后两个元素应该是已经排序好的第二大,和最大的元素,所以排除B,D,再因为每次排序都会两两交换,所以排除…

裸金属服务器,云用户的新体验

定义 裸金属服务器(Bare Metal Server),是一台既具有传统物理服务器特点的硬件设备,又具备云计算技术的虚拟化服务功能,是硬件和软件优势结合的产物。可以为企业提供专属的云上物理服务器,为核心数据库、关…

【010】基于springboot+vue的校园资产管理

【010】基于springbootvue的校园资产管理 一、系统情况介绍 该系统是基于springbootvue的校园资产管理系统,校园资产管理是一款可以真正提升管理者的办公效率的软件系统。主要有以下功能:个人信息管理、校园资产管理、资产借用管理、入库管理、用户管理…

[Java EE] 多线程(六):线程池与定时器

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀Java …

利用大语言模型(KIMI)构建智能产品的信息模型

数字化的核心是数字化建模,为一个事物构建数字模型是一件非常繁杂和耗费人工的事情。利用大语言模型,能够轻松地生成设备的信息模型,我们的初步实验表明,只要提供足够的模板,就能够准确地生成设备的数字化模型。 我们尝…

【CV-CUDA实战】使用Python+TensorRT+CVCUDA优化YOLOv8

目录 什么是CV-CUDA环境准备准备CV-CUDA静态库解压添加至变量将PyBind静态库复制到env下算子设计前处理算子 TensorRT模型加载后处理函数 完整代码输出演示为什么重新写了?结语 什么是CV-CUDA NVIDIA CV-CUDA™ 是一个开源项目,用于构建云规模人工智能 (…

cefsharp实现资源替换如网页背景、移除替换标签、html标识、执行javascript脚本学习笔记(含源码说明)

(一)实现测试(仅供学习参考) 1.1 目标系统页面(登录页)和登录后首页面中2处(一个替换一个移除) 1.2 实现后效果(使用cefsharp自定义浏览器实现以上功能) 1.3 登录后页面替换和移除 系统名称和一个功能菜单li (二)通过分析代码实现脚本编写 2.1 分开处理,设置了…

STM32中断之TIM定时器详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. TIM简述 2. 定时器类型 2.1 基本定时器 2.2 通用定时器 2.3 高级定时器 3. 定时中断 4. 代码示例1 5. 代码示例2 1. TIM简述 定时器的基本功能:定时器可以在预定的时间间隔内产生周…

网络安全之弱口令与命令爆破(中篇)(技术进阶)

目录 一,什么是弱口令? 二,为什么会产生弱口令呢? 三,字典的生成 四,使用Burpsuite工具验证码爆破 总结 笔记改错 一,什么是弱口令? 弱口令就是容易被人们所能猜到的密码呗&a…

基于LLama3、Langchain,Chroma 构建RAG

概要: 使用Llama3 Langchain和ChromaDB创建一个检索增强生成(RAG)系统。这将允许我们询问有关我们的文档(未包含在训练数据中)的问题,而无需对大型语言模型(LLM)进行微调。在使用RA…

mysql 指定根目录 迁移根目录

mysql 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、初始化mysql前就手动指定mysql根目录为一个大的分区(支持动态扩容),事前就根本上解决mysql根目录空间不够问题3.1.0、方法思路3.1.1、卸载mariadb3.1.2、下载Mysql安装包3.1.3、安装Mysql 8.353…

jupyter notebook使用与本地位置设置

本地安装好Anaconda之后,自带的有Jupter notebook。 使用jupyter notebook 使用jupyter notebook时,可以直接打开或者搜索打开: 打开后,我们生成的或者编辑的一些文件,都可以看到,如下: j…

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz,当板载8MHz晶振时,系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​,在文件stm32f4xx.h中可修…

uniapp 自定义相机插件(组件版、缩放、裁剪)组件 Ba-CameraView

自定义相机插件(组件版、缩放、裁剪) Ba-CameraView 简介(下载地址) Ba-CameraView 是一款自定义相机拍照组件,支持任意界面,支持裁剪 支持任意自定义界面支持手势缩放支持裁剪(手势拖动、比…

R语言中,查看经安装的包,查看已经加载的包,查看特定包是否已经安装,安装包,更新包,卸载包

创建于:2024.5.4 R语言中,查看经安装的包,查看已经加载的包,查看特定包是否已经安装,安装包,更新包,卸载包 文章目录 1. 查看经安装的包2. 查看已经加载的包3. 查看特定包是否已经安装4. 安装包…

【Cpp】类和对象#拷贝构造 赋值重载

标题:【Cpp】类和对象#拷贝构造 赋值重载 水墨不写bug 目录 (一)拷贝构造 (二)赋值重载 (三)浅拷贝与深拷贝 正文开始: (一)拷贝构造 拷贝构造函数&…

上位机开发PyQt(五)【Qt Designer】

PyQt5提供了一个可视化图形工具Qt Designer,文件名为designer.exe。如果在电脑上找不到,可以用如下命令进行安装: pip install PyQt5-tools 安装完毕后,可在如下目录找到此工具软件: %LOCALAPPDATA%\Programs\Python\…