【C++】hash:unordered_map和unordered_set的底层结构

news2024/12/22 20:34:04

hash

  • 哈希概念
  • 哈希冲突
  • 哈希函数
    • 哈希冲突的两种解决方法之闭散列
    • 哈希冲突的两种解决方法之开散列
    • 开散列和闭散列的比较

哈希概念

在c++98中还并没有提出哈希这样的结构,只有以红黑树为底层结构的map,set系列,这样使得查询时的效率 l o g 2 N log_2 N log2N,但是当出现大量的数据时,查询的效率也不理想,因此在c++11,又提出了4个关联式容器,也就是unordered系列,其底层结构为hash。

哈希函数:哈希结构中,使用哈希函数使元素的存储位置与它的关键码之间建立一一映射的关系,这样在查找时就可以通过该函数很快的查找到该元素了。
哈希表:通过哈希函数构造出来的结构称为哈希表。

哈希冲突

如图,对数据集合A为{1, 7, 6, 5, 9}进行哈希函数的映射,哈希函数设计为
hash(key) = key % capacity;capacity为底层空间大小。
那么对于集合A,首先将1,7,6,5,9放入哈希表中后,如果再放一个11,通过hash函数映射后本应该放入1这个位置,但是1这个位置已经有元素了,这时候就是哈希冲突。

在这里插入图片描述
也就是说,不同关键字通过相同hash函数计算出相同的哈希地址,这种现象就称为哈希冲突或者哈希碰撞。

哈希函数

引起哈希冲突的原因中有一个是:哈希函数设计的不合理。
对于一个哈希函数,在设计时就要有以下原则:

1.哈希函数的定义域要包含所有的key
2.哈希函数计算出来的地址能够均匀的分布在整个空间中。

我们常见的哈希函数有:

1.直接定址法
2.除留余数法
3.平方取中法
4.折叠法
5.随机数法
6.数学分析法

注意:哈希函数的设计越巧妙,只能使得哈希冲突出现的可能性越低,但是并不能完全避免哈希冲突

哈希冲突的两种解决方法之闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?
这里有两种方式:

1.线性探测: 也就是从冲突发生的位置开始,依次向后探测,直到找到下一个空位置为止。 那么对于线性探测来找空位置的方法来说,如果需要删除某个位置的元素,就不能直接删除了,因为要删除的位置可能并不是直接插入的,而是依次向后找了好多位置才找到的,贸然删除某个位置的元素,可能会导致其他的元素查找受到影响
对于线性探测来说,优点是实现简单,但是缺点是发生哈希冲突后,可能会造成数据的“堆积”,从而导致搜索效率下降。

2.二次探测: 二次探测就是为了解决数据堆积的问题,它的做法不是简单的向后依次找空位置,而是 H i H_i Hi = ( H 0 H_0 H0 + i 2 i^2 i2 )% m, 或者: H i H_i Hi = ( H 0 H_0 H0 - i 2 i^2 i2 )% m 其中:i =1,2,3…,
H 0 H_0 H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小。

研究表明:当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容。

哈希冲突的两种解决方法之开散列

对于闭散列的方式解决哈希冲突的方式来说,其空间利用率太低,这也是哈希的缺陷。

而开散列的做法是:
首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。我们也称之为哈希桶。

在这里插入图片描述
从上图可以看到,开散列中每个桶中放的都是发生哈希冲突的元素。

那么如果元素继续增加,哈希桶又该如何扩容呢?

桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希表进行增容,那该条件怎么确认呢?
开散列最佳情况是每个桶中只挂一个元素,那么设计为当元素个数等于桶的个数时,给哈希桶进行扩容。

开散列和闭散列的比较

开散列应用链地址法来处理哈希冲突,看似要增加链接指针,增加了存储开销,但是实际上闭散列由于要保持大量的空闲空间,以确保搜索效率(线性探测要求装载因子<= 0.5, 二次探测要求装载因子 <= 0.7)都会浪费大量的空间,因此综合来看,开散列比闭散列要更加节省空间

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

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

相关文章

c语言修炼第二章--分支与循环

目录 前言 2.1分支语句 2.1.1什么是语句 2.2分支语句 2.2.1if语句的语法形式 2.2.2悬空else问题 2.2.3if书写形式的对比 2.3switch语句 2.3.1switch的语法形式 2.3.2 switch与break的关系 2.3.3 switch与default的关系 前言 小伙伴们端午安康吖&#xff01;今天我们…

Mac菜单栏快捷开关 One Switch

One Switch是一款简单易用的 macOS 应用程序&#xff0c;它可以帮助用户快速地切换和管理 Mac 电脑的各种系统设置。这款应用程序提供了一个干净简洁的界面&#xff0c;让用户可以快速地启用或禁用诸如 Wi-Fi、蓝牙、Night Shift、暗色模式、Do Not Disturb 等功能。用户可以通…

建立无需build的vue单页面应用SPA框架

vue、react这种前端渲染的框架&#xff0c;比较适合做SPA&#xff08;Single Page Application&#xff09;。如果用ejs做SPA&#xff0c;js代码控制好全局变量冲突不算严重&#xff0c;但dom元素用jquery操作会遇到很多的名称上的冲突&#xff08;tag、id、name&#xff09;。…

运动蓝牙耳机怎么选、好用的运动蓝牙耳机推荐

在快节奏的现代生活中&#xff0c;运动成为了释放压力、保持健康和放松身心的重要方式。跑步、健身、骑行等各类运动成为了人们日常生活中不可或缺的一部分。然而&#xff0c;一场精彩的运动体验离不开动感的音乐伴奏。为了满足人们对高品质音乐的追求&#xff0c;一款出色的运…

nvm安装、管理多个node版本

1、官网下载nvm https://github.com/coreybutler/nvm-windows/releases 2、解压ZIP&#xff0c;双击nvm-setup.exe(假如以前安装了node.js&#xff0c;把以前的卸载了再安装nvm) 3、安装nvm 注意&#xff1a;这一步的nodejs目录需要手动创建 4、安装完毕&#xff0c;设置下载镜…

OpenCV动态人物识别代码

动态人物识别代码 int main() {// 打开视频文件或摄像头VideoCapture cap("vtest.avi");// VideoCapture cap(0); // 使用默认摄像头if (!cap.isOpened()){std::cout << "无法打开视频文件或摄像头流" << std::endl;return -1;}// 读取第一帧…

幽灵依赖是什么,pnpm出现的意义,使用pnpm创建一个vue3项目

什么是幽灵依赖&#xff08;幻影依赖&#xff09; 比如我们创建一个全新的vue3项目 然后我们正常地通过npm install来下载依赖 然后我们发现&#xff0c;node_ modules文件夹下的很多依赖&#xff0c;我们在package.json中明明没去声明却都下载下来了 那么这些没声明却下载…

SQL-游标-查询

/***DB版本&#xff1a;SQL Server 2022***/ --切换数据库 use MyDatabase--创建游标(scroll&#xff1a;滚动游标) declare mycur cursor scroll for select EmpNo from Employee--打开游标 open mycur --提取第一行 fetch first from mycur --提取最后一行 fetch last from m…

ansible自动化安装及简单操作

目录 一、运行机制 二、安装 1.下载ansible 2.配置免密 3.修改配置文件 4.创建主机清单 5.远程安装 6.远程卸载 一、运行机制 Ansible&#xff1a; ansible的核心模块 Host Inventory&#xff1a;主机清单&#xff0c;也就是被管理的主机列表 Playbooks&…

实战打靶集锦-021-glasgowsmile

提示&#xff1a;本文记录了博主的一次曲折的打靶经历。 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 手工访问4.2 目录枚举4.3 手工探查4.4 搜索EXP4.5 joomlascan4.6 用户猜测与密码爆破4.7 构建反弹shell 5. 提权5.1 优化shell5.2 枚举系统信息5.3 探查/etc/pass…

虚拟机VMware+Ubuntu配置DPDK环境并运行Helloworld

虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld 文章目录 虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld安装虚拟机虚拟机中安装DPDK运行Helloworld 首先需要强调的是&#xff0c;版本的影响很大&#xff0c;有可能会因为版本不匹配而导致无法成功配置DPDK环境。 安装虚拟…

【Leetcode -637.二叉树的层平均值 -671.二叉树中第二小的节点】

Leetcode Leetcode -637.二叉树的层平均值Leetcode -671.二叉树中第二小的节点 Leetcode -637.二叉树的层平均值 题目&#xff1a;给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10^(- 5) 以内的答案可以被接受。 示例 1&#xff1…

TCP服务器的C#实现

1、TCP实现类 internal class TcpServer{public Socket ServerSocket { get; set; }public Dictionary<string,Socket> Sockets { get; set; } new Dictionary<string,Socket>();public byte[] SendBuffer { get; set; }public byte[] ReceiveBuffer { get; set; …

Qt消息对话框

一、头文件及类型 #include<QMessageBox> 二、错误、信息、提示、警告演示 错误对话框 QMessageBox::critical(this,"critical","错误"); 信息对话框 QMessageBox::information(this,"info","信息"); 提问对话框 if(QMessageBo…

发布自己的第一个抖音小程序

结构与微信小程序一样 内嵌H5网页&#xff0c;适用于任何平台&#xff0c;同样也是使用web-view组件 <web-view src"https://some-domain/some/path"></web-view> 相比起来&#xff0c;它比微信小程序更加简化&#xff0c;开发会更方便了。 API查询地…

超越Java 7,迎接Java 8时代!掌握这些新特性提升你的编程技能!

大家好&#xff0c;我是小米&#xff0c;一个热衷于技术分享的小伙伴。今天&#xff0c;我将向大家介绍Java 8中的一些新特性。Java 8作为一次重大更新&#xff0c;引入了许多令人激动的新功能&#xff0c;让我们的编码变得更加简洁高效。接下来&#xff0c;我们将详细介绍这些…

【暂时解决】radio单选框的change事件执行两次

项目场景&#xff1a; 简单的单选框场景 选择国内地区&#xff0c;省市县的下拉框就显示&#xff0c;选择国外地区就隐藏。 问题描述 当我使用radio的change事件时&#xff0c;会执行两次 javascript&#xff1a; $(input[typeradio][nameoptionsRadios]).change(function …

黑产科普丨揭秘游戏黑灰产业链

自今年起&#xff0c;游戏版号已恢复常态化发放&#xff0c;游戏行业在官方发文肯定、重获资本青睐、AI降本增效等多方助力下持续回暖。暑期档将至&#xff0c;游戏厂商为了抢占更多的市场份额&#xff0c;占据更多的玩家视野&#xff0c;将有大量的游戏选择在这个时间上线。 …

datax-Oracle新增writeMode支持

1.在com.alibaba.datax.plugin.writer.oraclewriter.OracleWriter中注释此内容,以让oracle支持writeMode模式 2.在com.alibaba.datax.plugin.rdbms.writer.util.WriterUtil中,增加对oracle的判断,将getWriteTemplate修改为如下内容 public static String getWriteTemplate(List…

在文件夹中获取某个文件的绝对路径

#!/bin/bash -lpathfind $(pwd) -name *.ipaecho ${path}写成下面这样也是可以的 path$(find $(pwd) -name *.ipa)如图所示&#xff0c;Export 文件夹下有.ipa文件&#xff0c;我们目前想获取.ipa文件的绝对路径 执行结果如下 192:Jenkins liubo$ cd /Users/liubo/Desktop/…