go语言map底层及扩容机制原理详解(上)
底层数据结构-哈希表
go语言map的底层数据结构是哈希表:通过哈希表来存储键值对,通过hash函数把键值对散列到一个个桶(bucket)中。
什么是哈希表?
- 在顺序结构以及平衡树中,元素与其的存储位置之间没有对应关系,因此查找一个元素时,必须进行多次比较。所以顺序查找的时间复杂度为O(N),而平衡树中则为树的高度O(log2N)。
- 为了减少搜素时元素比较的次数,是否有一种方法可以不经过任何比较,通过元素的存储位置与它的关键码以O(1)的时间复杂度直接找到该元素呢?
- 哈希表就是通过某种函数(hash)来使元素的存储位置和其元素值之间建立一一映射的关系,那么就可以通过这种关系快速找到该元素。(数组就是一种简单的哈希表)
如何处理哈希冲突?
- 当两个或多个健具有相同的哈希值,即为出现了哈希冲突,它们会被存放在同一个桶中。go采用拉链法来解决哈希冲突的问题,即在同一个桶内部通过链接(链表)存储所有冲突的键值对。
- 不过拉链法在当哈希冲突出现的次数相当频繁时,会将常数级的时间复杂度上升甚至到线性级。加载因子的出现就是为了避免过多的哈希冲突导致哈希表的退化。
无序性
- 由于go语言的map是通过哈希表来实现的,由于哈希函数的特性,是无法依据一定的顺序来存储的。因此go的
map
是无序的。
map的扩容机制
在哈希表中,当元素达到一定的数量(超过加载因子设定的比例),为了保持操作的效率,需要对哈希表进行扩容。扩容通常需要创建一个更大的哈希表,并将现有元素重新映射到新表中。
底层实现
type hmap struct {count int // 元素的个数B uint8 // buckets 数组的长度就是 2^B 个overflow uint16 // 溢出桶的数量buckets unsafe.Pointer // 2^B个桶对应的数组指针oldbuckets unsafe.Pointer // 发生扩容时,记录扩容前的buckets数组指针extra *mapextra //用于保存溢出桶的地址
}type mapextra struct {overflow *[]*bmapoldoverflow *[]*bmapnextOverflow *bmap
}type bmap struct {tophash [bucketCnt]uint8
}//在编译期间会产生新的结构体
type bmap struct {tophash [8]uint8 //存储哈希值的高8位data byte[1] //key value数据:key/key/key/.../value/value/value...overflow *bmap //溢出bucket的地址
}
在go的map实现中,它的底层结构体是hmap,hmap里维护着若干个bucket数组 (即桶数组)。每个桶中保存了8个键值对,如果8个满了,又来了一个kv到了这个桶中,会使用overflow连接下一个桶,即桶溢出。
- 对于哈希冲突:当两个不同的key落到了同一个桶中就是发生了哈希冲突,则会采用拉链法,从前往后找一个空位进行插入。如果桶满了,当前桶就会连接到下一个溢出桶。
扩容基本步骤
- 触发扩容:
- 当向
map
中添加新元素时,如果元素数量超过了当前哈希表容量和加载因子的乘积,就会触发扩容。加载因子是一个决定性能与内存使用之间的阈值,防止哈希表的退化。
- 当向
- 分配新表
- go在运行是会创建一个新的哈希表,其容量为原来的两倍。这样做可以减少再次扩容的可能,并提供足够的空间来避免过多的哈希冲突。
- 数据迁移
- 将旧哈希表中的现有元素迁移到新表中。每个元素的哈希中将根据新表的大小容量重新计算,来确定它们在新表的位置。
- 当
map
非常大的情况下,每次迁移所有的元素,会出现长时间的暂停。在go1.8版本之后,这个步骤是渐进式的:每次向map`添加新元素或查找时,都会迁移一小部分元素,避免长时间的暂停。
- 更新引用
- 当所有元素都迁移到新的哈希表中后,原来的哈希表将会被丢弃,
map
的内部引用将指向新表。
- 当所有元素都迁移到新的哈希表中后,原来的哈希表将会被丢弃,
总结
- 要提供合适的初始容量。
由于每次扩容时,需要重新计算所有元素的哈希值并将它们分配到新的桶中,这是一个相当花时间的操作。因此,如果我们事先知道map
大约会存储多少数据,可以实现在创建map
时通过提供合适的初始容量来减少扩容次数,从而提高map
的性能:
myMap := make(map[string]int, initialCapacity)
相关文章:
go语言map底层及扩容机制原理详解(上)
底层数据结构-哈希表 go语言map的底层数据结构是哈希表:通过哈希表来存储键值对,通过hash函数把键值对散列到一个个桶(bucket)中。 什么是哈希表? 在顺序结构以及平衡树中,元素与其的存储位置之间没有对应关系,因此…...

互联网职场说 | “领导找我谈话,原来是给我涨薪,但却只涨了200,还偷偷叮嘱我保密,这次只给我涨了薪”
职场中,一般当领导找你谈话时,心里总是会涌起两种心理活动:问责和表扬。不过很多人第一反应就是有点担心害怕,其次才会想有什么好事临到我了! 一位职场网友分享说,有天领导忽然找她谈话,当时心…...

Android 如何启用user版本的adb源码分析
Android调试桥(ADB, Android Debug Bridge)是一个Android命令行工具,包含在SDK 平台工具包中,adb可以用于连接Android设备,或者模拟器,实现对设备的控制,比如安装和调试应用。和Appium一样,adb也是基于C/S架…...

linux phpstudy 重启命令
[rootLinuxWeb phpstudy]# ./system/phpstudyctl restart 查看命令 1) phpstudy -start 启动小皮面板 2) phpstudy -stop 停止小皮面板 3) phpstudy -restart 重启小皮面板 4) phpstudy -status 查询面板状态 5) phpstudy -in…...

台式电脑屏幕亮度怎么调节?让你的眼睛更舒适!
在日常使用台式电脑时,调节屏幕亮度是一项常见的需求。不同的环境和个人偏好可能需要不同的亮度设置。因此,了解台式电脑屏幕亮度怎么调节是非常重要的。本文将介绍三种常见的方法,帮助您轻松调节台式电脑屏幕亮度,以满足您的需求…...
打造安全的 Linux 环境:实用配置指南
唠唠闲话 一开始接触服务器,我只是把它当博客的托管网站,源文件用 GitHub 备份,所以网站被黑了也没啥关系。但随着使用深入,网站逐渐加入我的日常工作流中,而且有了使用更多服务的需求。在这种情况下,服务…...
神经网络有哪些算法
神经网络算法是人工智能领域的重要组成部分,它通过模拟人类神经系统的结构和功能,实现对复杂问题的处理和分析。以下是对神经网络算法的详细概述,包括常见的算法和它们的特点、应用等,力求达到约2500字的篇幅。 一、神经网络算法概述 神经网络算法是一种基于人工神经元的…...
计算机网络期末试题
第一章 概述 一. 单选题(共13题,36.4分) 1. (单选题) 因特网起源于( )网络。 A. ARPANETB. EthernetC. CATVD. CERNET 我的答案: A:ARPANET;正确答案: A:ARPANET; 2.8分 2. (单选题)人们把( )年作为因特网的诞…...
Unity学习笔记---图层
渲染层级 1,调整Sprite Renderer中的Order in Layer可以调整图层层级。 2,在Edit--Project Setting--Graphics中,调整TransParency Sort Mode为Custom Axis, 并将TransParency Sort Axis中的Z值默认的1改为0,将Y改为…...

【简单探索微软Edge】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...

YOLOv5独家改进:backbone改进 | 微软新作StarNet:超强轻量级Backbone | CVPR 2024
💡💡💡创新点:star operation(元素乘法)在无需加宽网络下,将输入映射到高维非线性特征空间的能力,这就是StarNet的核心创新,在紧凑的网络结构和较低的能耗下展示了令人印象深刻的性能和低延迟 💡💡💡如何跟YOLOv5结合:替代YOLOv5的backbone 收录 YOL…...
概率密度函数pdf的某种解释与洞察
1.一个想法实验 我在想一个数,姑且称之为X,介于0和10之间(含0和10)。如果我不告诉你别的,你会想象X = 0的概率是多少?X = 4?假设我对任何特定的数字都没有偏好,你会想象十一个整数0,1,2,.….,10也是一样。因为所有的概率加起来必须是1,所以逻辑上的结论是给11个选项…...
【OceanBase诊断调优】—— 转储错误(错误代码 4138/ORA-01555)
当读事务很长时,租户进行转储会报 4138/ORA-01555 错误。本文介绍该错误的处理方法。 适用版本 OceanBase 数据库 V2.X 及以后的版本 问题现象 当读事务很长,租户进行转储时会出现以下错误。 Oracle 租户: ORA-01555:snapsho…...
Python面试题【数据结构和算法部分101-130】
Python面试题【数据结构和算法部分101-130】 Python面试题【数据结构和算法部分101-130】 Python面试题【数据结构和算法部分101-130】 问题:如何在Python中实现二分查找? 答案: def binary_search(arr, target):low, high 0, len(arr) - 1…...
Django中的日志处理
日志处理 1.日志级别 级别(Level)表示日志消息的优先级,从低到高分为以下几个级别: DEBUG: 详细的日志信息,通常用于调试。 INFO: 一般的信息性消息,用于说明程序运行情况。 WARNING: 警告消息࿰…...

FonePaw Data Recovery for Mac:轻松恢复丢失数据
FonePaw Data Recovery for Mac是一款功能强大的数据恢复软件,专为Mac用户设计,帮助用户轻松恢复因各种原因丢失的数据。该软件支持从硬盘驱动器、存储卡、闪存驱动器等存储介质中恢复丢失或删除的文件,包括照片、视频、文档、电子邮件、音频…...

C语言易错提醒选择题精选
Ⅰ 易错题 1.设有double p;,为变量p声明一个引用名称rp,则定义语句为 double& rpp; 2.已知‘A’一‘Z’的ASCII码为65—90,当执行“char ch14*52;cout<<ch<<endl;”语句序列后得到的输出结H ,72对应ASCII码中…...
Android11系统去掉截屏功能
1. 去掉Settings里截屏菜单条目,packages/apps/Settings: diff --git a/res/xml/top_level_settings.xml b/res/xml/top_level_settings.xml old mode 100644 new mode 100755 index a5e4d06..a9420bb --- a/res/xml/top_level_settings.xmlb/res/xml/t…...
测试驱动来学习 Promise
基础功能 测试案例:以同步的方式调用。 /*** v1: 基础功能*/ const p1 new MyPromise((resolve, reject) > {resolve(success)reject(error) })p1.then((value) > {console.log(v1: , value) }) 实现功能:在 status 和 value 的位置暂存值&…...

Vue3实战笔记(20)—封装头部导航组件
文章目录 前言一、封装头部导航栏二、使用步骤总结 前言 Vue 3 封装头部导航栏有助于提高代码复用性、统一风格、降低维护成本、提高可配置性和模块化程度,同时还可以实现动态渲染等功能,有利于项目开发和维护。 一、封装头部导航栏 封装头部导航栏&am…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...