golang中map原理剖析
1. golang中的map有自己的一套实现原理,其核心是由hmap和bmap两个结构体实现的
2. 初始化map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package main func main() { // 初始化一个可容纳10个元素的map map1 := make( map [string]string, 10) // 第一步:创建一个hmap结构体对象 // 第二步:生成一个哈希因子hash0并赋值到hmap对象中(用于后续为key创建哈希值) // 第三步:根据hint=10,并根据算法规则来创建B,当前B应该为1 /* hint B 0~8 0 9~13 1 14~26 2 ... */ // 第四步:根据B去创建桶(bmap对象)并存在buckets数组中,当前bmap的数量应为2 // 当B<4时,根据B创建桶的个数的规则为:2的B次方(标准通) // 当B>=4时,根据B创建桶的个数的规则为:2的B次方 + 2的(B-4)次方(标准通+溢出桶) // 注意:每个bmap中可以存储8个键值对,当不够存时需要使用溢出桶,并将当前bmap中的overflow字段指向溢出桶的位置 } |
3. map写入数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | map1[ "name" ] = "武沛齐" // 第一步:结合哈希因子和键name生成哈希值 // 第二步:取哈希值的后B位,并根据后B位的值来决定将此键值对存放到哪个桶中(bmap)。 /* 将哈希值和桶掩码(B个为1的二进制)进行&运算,最终得到哈希值的后B位的值,假设当B为1时,其结果为0 哈希值:0101001111001011010 桶掩码:0000000000000000001 结果: 0000000000000000000 = 0 通过示例你会发现,找桶的原则实际上是根据后B位的位运算计算出索引位置,然后再去buckets数组中根据索引找到目标桶(bmap)。 */ // 第三步:在上一步确定桶之后,接下来就在桶中写入数据 /* 获取哈希值的tophash(即:哈希值的'高8位'),将tophash,key,value分别写入到桶中的三个数组中 如果桶已满,则通过overflow找到溢出桶,并在溢出桶中继续写入。‘ 注意:以后在桶中查找数据时,会基于tophash来找,(tophash相同则再去比较key) */ // 第四步:hmap的个数count++(map中的元素个数+1) |
4. map读取数据
1 2 3 4 5 | value := map1[ "name" ] // 第一步:结合哈希因子和键name生成哈希值。 // 第二步:获取哈希值的后B位,并根据后B位的值来决定将此键存放到哪个桶中(bmap)。 // 第三步:确定桶之后,在根据key的哈希值计算出tophash(高8位),再根据tophash和key去桶中查找数据。 // 当前桶如果没有找到,则根据overflow在去溢出桶中找,均未找到则表示key不存在 |
5. map扩容
1 2 3 4 5 6 | // 在向map中添加数据时,当达到某个条件,则会引发map扩容 // 扩容条件 // 1. map中数据总个数/桶个数>6.5时,引发翻倍扩容 // 2. 使用了太多的溢出桶时,(溢出桶使用的太多会导致map处理速度降低) // B <= 15,已使用的溢出桶个数 >=2的B次方时,引发等量扩容 // B > 15,已使用的溢出桶个数 >=2的15次方时,引发等量扩容 |
6. map中数据迁移
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)