【数据结构】-----哈希

目录

一、哈希表概念

二、哈希函数

三、哈希冲突

Ⅰ、定义

 Ⅱ、解决

①闭散列--开放定址法

线性探测

 二次线性探测

②开散列--链地址法(哈希桶)

问题:哈希表何时扩容?


一、哈希表概念

哈希表又称散列表,它是一种数据存储结构,该结构主要是通过某种哈希函数将元素的存储位置与元素的关键码(值)之间建立起一种一一映射的关系。因此在查找时能够通过该哈希函数直接找到对应的元素,效率上明显提高。

例如:存在数据集合{1,3,6,2,4};

哈希函数设置为:hash(key)=key % capacity。capacity为存储元素底层空间总大小。

假设这里的capacity大小为10,则各元素之间的存储位置如下:

用该方法进行搜索不必进行多次关键码的比较,因此速度会很快!

在理想情况下:哈希表的查找可以达到O(1)。而顺序查找和平衡树中,因为值和位置之间没有直接的关系,查找需要进行多次比较,顺序查找O(N),平衡树查找为树的高度,即O(log_2N)。搜索的效率取决于元素的比较次数,相比于哈希,挺慢!

二、哈希函数

哈希函数设计的原则:

  • 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
  • 哈希函数计算出来的地址能均匀分布在整个空间中
  • 哈希函数应该比较简单

 常见哈希函数: 

  • 直接定址法(常用)

取关键字的某个线性函数为散列地址:Hash(Key)=key 或者 Hash(Key)= A*Key + B
优点:简单、均匀
缺点:需要事先知道关键字的分布情况
使用场景:适合查找比较小且连续的情况

  • 除留取余法(常用)

 设散列表中允许的地址数为m(空间总容量),取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址。

优点:使用十分广泛,不受限制。

缺点:存在哈希冲突,哈希冲突越多,效率越低。

  • 平方取中 

 假设关键字为123,平方后15129,抽取中间3位512作为哈希地址。

再如关键字4321,平方后18671041,抽取中间3位671或者710作为哈希地址。

该方法适用于:不知道关键字的分布情况,而位数又不是很大的情况。

  • 折叠法 

折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这
几部分叠加求和,并按散列表表长,取后几位作为散列地址。

适用于:不知道关键字的分布情况,而位数多的情况。

如:123456789  ->分割:123|456|789 ->相加:123+456+789=1368

假设表长为10,那就取后两位68作为哈希地址。

  • 随机数法 

 选择一个随机函数,取关键字的随机函数值为它的哈希地址,即Hash(key) = random(key),其中random为随机数函数。
通常应用于关键字长度不等时采用此法

用得多还是前面两个,其他简单了解即可! 

三、哈希冲突

Ⅰ、定义

所谓哈希冲突,就是不同的关键码通过同一个哈希函数计算得到相同的存储地址。即相同位置上存在不同的值的现象。

引起哈希冲突的原因可能就是:哈希函数设计不合理引起的!

例如:在上述例子再插入11,计算后得到的地址为下标1,和原来的1发生的冲突,那么该怎么去解决呢?

 Ⅱ、解决

常见两种方法:闭散列 和 开散列

①闭散列--开放定址法

此法又称开放定址法,当发生哈希冲突时,如果哈希表未装满,说明有空位置,那么可以把key存放到冲突位置的下一个空位置去,这里寻找下一个空位置的方法又有两种

  • 线性探测

 这种方式是从发生冲突的位置开始,依次向后探测,直到发现下一个空位置为止

H=(Hash0+i)%m ,i=1,2,3……

Hash0:通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,即Hash(key)

m:散列表长度,这里取余,是为防止越界从而达到循环的效果。。

例如:上述例子插入11,通过哈希函数取余操作后发现和原来的1的位置冲突了,那就要继续向后探测,依次+1,+2,……,直到发现空位置,就放入该位置!

优点:实现简单

缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,即:不同
关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降
低。所以需要扩容操作!

  •  二次线性探测

这种探测方式能够避免线性探测的数据堆积问题的,它和线性探测的区别就是:依次跨越i^2 个单位,i从1开始。数据之间会相对稀疏。

H=(Hash0+i^2)%m ,i=1,2,3……

上述例子的过程如下:

插入11,发现冲突,第一次探测先加1^2,第二次探测加2^2,发现了空位置直接放入即可

②开散列--链地址法(哈希桶)

开散列法又称为链地址法,当发生哈希冲突时,将相同地址的值归于同一个子集合每一个子集合称为一个桶,这个桶里面的元素采用链表的方式链接起来。即每一个桶存放的都是冲突的数据!

还是以上述例子举例。插入元素11,发生冲突,采用开散列的方式,无需向后寻找空位置,直接采用头插法。。

问题:哈希表何时扩容?

这里就需要引入负载因子的说法:负载因子\alpha=有效数据个数 / 散列表长度。

从上述公式可以看出:当数据个数越多,负载因子越高,冲突率越高,效率就越低;当长度越长,负载因子越低,冲突率越低,效率就越高,但此时空间利用率就越低。

哈希表的平均查找长度是负载因子\alpha的函数,即每个元素比较次数总和 / 元素总个数

  • 对于闭散列来说,一般严格将负载因子控制在0.7-0.8之间。超过0.8查表时,cpu缓存不命中按照指数曲线上升。因此采用闭散列的方式,保险起见超过0.7就需要扩容操作
  • 对于开散列来说,最好的情况是每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数(散列表长度)时,即负载因子等于1时,就可以给哈希表增容

具体如何扩容,请看下一回实现部分,因为看到这里,您也累了,休息一下咯!


好了,老铁今天的分享内容就到这里,觉得对你有帮助,欢迎点赞+关注!

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

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

相关文章

python网络爬虫(四)——实战练习

0.为什么要学习网络爬虫 深度学习一般过程:   收集数据&#xff0c;尤其是有标签、高质量的数据是一件昂贵的工作。   爬虫的过程&#xff0c;就是模仿浏览器的行为&#xff0c;往目标站点发送请求&#xff0c;接收服务器的响应数据&#xff0c;提取需要的信息&#xff0c…

【408DS算法题】034进阶-22年真题_判断顺序存储二叉树是否是BST

Index 真题题目分析实现总结 真题题目 已知非空二叉树T的结点值均为正整数&#xff0c;采用顺序存储方式保存&#xff0c;数据结构定义如下: typedef struct { // MAX_STZE为已定义常量int SqBiTNode[MAX_SIZE]; // 保存二叉树结点值的数组int ElemNum; …

java 常用并发队列- DelayQueue

1. 什么是 DelayQueue&#xff1f; DelayQueue 是一个支持 延迟获取元素 的阻塞队列&#xff0c;它的元素必须实现 java.util.concurrent.Delayed 接口&#xff0c;该接口要求元素定义一个 getDelay(TimeUnit unit) 方法&#xff0c;用来指定元素何时可以从队列中取出。DelayQ…

Python简易IDE工作界面制作

、 休闲一下&#xff0c;学习编程还是要学习一些界面编程&#xff0c;能够根据需要制作图形操作界面&#xff0c;这样我们开发的程序才能方便操作和使用&#xff0c;同时获得更友好的人机交互体验。下面是一个用PyQt5制作的简易界面&#xff0c;供大学参考。如下图所示&a…

【淘宝采集项目经验分享】商品评论采集 |商品详情采集 |关键词搜索商品信息采集

商品评论采集 1、输入商品ID 2、筛选要抓取评论类型 3、填写要抓取的页数 4、立刻提交-启动测试 5、等爬虫结束后就可以到“爬取结果”里面下载数据 商品详情采集 1、输入商品ID 2、立刻提交-启动爬虫 3、等爬虫结束后就可以到“爬取结果”里面下载数据 taobao.item_…

【Python】Python 读取Excel、DataFrame对比并选出差异数据,重新写入Excel

背景&#xff1a;我在2个系统下载出了两个Excel&#xff0c;现在通过对下载的2个Excel数据&#xff0c;并选出差异数据 从新写入一个新的Excel中 differences_url rC:\Users\LENOVO\Downloads\differences.xlsx; //要生成的差异Excel的位置及名称 df1_url rC:\Users\LENOVO\Dow…

【 WPF 中常用的Brush类的简要介绍、使用方法和适用场景】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 WPF 中常用的 Brush 类的简要介绍、使用方法和适用场景 使用场景解释示例代码&#xff08;为按钮创建一个线性渐变背景&#xff09; Brush 类描述使用示例适用场景SolidColor…

cocotb备忘录

按位给和int int后接的值&#xff0c;建议在32之内。大于32位建议按位给&#xff0c;因为int强制类型转换有范围 第二&#xff0c;低位给到低位&#xff0c;高位给到高位 # 将src_ip和dst_ip给到phv中,TMD以后只要报错在这个范围里面&#xff0c;TMD直接马上用手算一遍能不能…

0903,LIST(merge,splice,sort,unique),SET(insert,erase)

目录 03_vector_delete.cc 04_vector_shrink.cc 05_vec_emplace_back.cc 06_listspec_splice.cc 07_classstruct.cc 08_set.cc 09_setErase.cc 作业 01 STL中的容器包括哪些&#xff1f;各自具有哪些特点&#xff1f; 02 题目&#xff1a;编写代码&#xff1a;将…

Docker设置socks5代理

查看测试环境 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy修改 Docker 服务代理配置文件 $ sudo mkdir -p /etc/systemd/system/docker.service.d $ sudo vi /etc/systemd/syst…

使用Spring Boot拦截器实现时间戳校验以防止接口被恶意刷

使用Spring Boot拦截器实现时间戳校验以防止接口被恶意刷 在开发Web应用程序时&#xff0c;接口被恶意刷请求&#xff08;例如DDoS攻击或暴力破解&#xff09;是一个常见的安全问题。为了提高接口的安全性&#xff0c;我们可以在服务端实现时间戳校验&#xff0c;以确保请求的…

基于Spring的消息推送实战(Websocket和前端轮询实现)

基于Spring的消息推送实战&#xff08;Websocket和前端轮询实现&#xff09; 本文介绍了基于Spring的消息推送实现方法&#xff0c;主要介绍了websocket实时消息推送方法&#xff08;ServerEndpoint方式实现&#xff09;&#xff0c;以及前端客户端轮询方式的消息推送。 一、消…

【Qt】 QComboBox | QSpinBox

文章目录 QComboBox —— 下拉框QComboBox 属性核心方法核心信号QComboBox 使用 QSpinBox —— 微调框QSpinBox 属性核心信号QSpinBox 使用 QComboBox —— 下拉框 QComboBox 属性 QComboBox —— 表示下拉框 currentText ——当前选中的文本 currentindex ——当前选中的条…

如何在虚拟机中安装部署K8S?

教程参考&#xff1a;centos7安装k8s 1.28版本&#xff0c;基于科学-CSDN博客 环境准备&#xff1a; 准备三台机器&#xff0c;都做以下操作&#xff0c;或者只准备一个机器&#xff0c;最后再克隆两台。 yum&#xff1a; 换源&#xff0c;这是阿里云的源 sudo wget -O /etc…

详解Asp.Net Core管道模型中的五种过滤器的适用场景与用法

1. 前言 在 ASP.NET Core 中&#xff0c;过滤器是一种用于对请求管道进行前置或后置处理的组件。它们可以在请求处理的不同阶段干预和修改请求和响应&#xff0c;以实现一些通用的处理逻辑或功能增强。 ASP.NET Core 的管道模型由多个中间件组成&#xff0c;而过滤器是这个模…

kafka及异步通知文章上下架

1)自媒体文章上下架 需求分析 2)kafka概述 消息中间件对比 特 性 ActiveMQ RabbitMQ RocketMQ Kafka 开 发 语 言 java erlang java scala 单 机 吞 吐 量 万级 万级 10万级 100万级 时 效 性 ms us ms ms级以内 可 用 性 高&#xff08;主从&#xff0…

如何从 Bak 文件中恢复 SQL数据库?(3种方法)

如何从 .bak 文件恢复 SQL数据库&#xff1f; 在数据库管理和维护过程中&#xff0c;数据的安全性和完整性至关重要。备份文件&#xff08;.bak 文件&#xff09;是 SQL Server 中常用的数据库备份格式&#xff0c;它包含了数据库的完整副本&#xff0c;用于在数据丢失、系统故…

flutter与原生怎么交互的

Flutter 与原生平台(如 Android 和 iOS)之间的交互可以通过**平台通道(Platform Channels)**实现。这允许你在 Flutter 应用中调用原生代码,或者从原生代码中调用 Flutter 代码。这种机制使得你可以利用原生平台提供的特性和 API,同时保持大部分应用代码在 Flutter 中。 …

4. 第一个3D案例—创建3D场景

入门Three.js的第一步&#xff0c;就是认识场景Scene、相机Camera、渲染器Renderer三个基本概念&#xff0c;接下来&#xff0c;咱们通过三小节课&#xff0c;大家演示“第一个3D案例”完成实现过程。 学习建议&#xff1a;只要你能把第一个3D案例搞明白&#xff0c;后面学习就…

二百六十、Java——采集Kafka数据,解析成一条条数据,写入另一Kafka中(复杂JSON)

一、目的 由于部分数据类型频率为1s&#xff0c;从而数据规模特别大&#xff0c;因此完整的JSON放在Hive中解析起来&#xff0c;尤其是在单机环境下&#xff0c;效率特别慢&#xff0c;无法满足业务需求。 而Flume的拦截器并不能很好的转换数据&#xff0c;因为只能采用Java方…