Golang 哈希表底层实现原理

1、本文讨论Golang的哈希表

Golang哈希表的实现,底层数据结构是数组+单链表,链表节点由8个key、value和键的高八位组成的。为了方便理解,先简单看一个图快速理解。
在这里插入图片描述

我们来看一下Golang哈希表的结构体定义
在这里插入图片描述

简单介绍一下结构体中几个关键的字段,hmap结构体就是Golang哈希表的底层结构体。

buckets为 哈希表 底层实际存储哈希表数据(数组+单链表)的指针变量

oldbuckets,也是存储哈希表数据(数组+单链表)的指针变量。但是,这个oldbuckets是用来存储 旧数据 的,用于在哈希表扩容时,渐进式扩容使用的,渐进式扩容结束时,oldbuckets指向的数据会被删除。后面我们再说扩容的事情。

count 表示当前哈希表中的元素数量,有一个很重要的意义就是,可以通过count知道渐进式扩容什么时候结束

hash0是哈希值的随机种子,这些都不是很重要。

extra是存储溢出桶的,溢出桶其实也是数组+单链表,可以简单理解成它的目的,是为了降低扩容频率而产生的

什么是桶,笔者理解其实就是那个底层数组。。。

介绍完关键几个字段,我们再看一张图便于理解

在这里插入图片描述

可以看到buckets指向的是一个数组,那么数组元素bmap就是一个“单链表”,所以才说Golang哈希表是数组+单链表,我们来看看bmap的数据结构

在这里插入图片描述

链表节点由8个keyvalue键的高八位组成的,overflow是指向下一个节点的指针,topbits就是8个键的高八位,作用是为了加速查找

其实到这里,你已经明白了哈希表整体的结构,那么我们来说说Golang哈希表是什么时候触发扩容扩容行为是什么

2、什么时候触发扩容

(1)溢出桶过多,也就是底层数组过长的时候
(2)负载因子达到某个阈值的时候

为什么溢出桶过多,也会触发扩容行为?

因为当溢出桶过多,但是桶中数据很少的时候。因为这时候键值对比较分散查找性能比较差,需要将键值对聚集一下

3、扩容行为有什么

(1)等量扩容

等量扩容,就是溢出桶过多,也就是底层数组过长的时候触发的,只是把键值对存储的更密集一些

(2)翻倍扩容

创建两倍桶数量两倍数组长度),然后将旧数据渐进式扩容的方式迁移旧数据,新数据直接写到新的桶中,我们看一个图方便理解,什么时候结束扩容?我们之前说了一个count字段,我们记录一下迁移了多少个,就知道是否完全迁移结束了

在这里插入图片描述

什么是渐进式扩容

①就是不一次性把数据复制过去,如果数据量多大,会短时间消耗大量性能

②首先把扩容前的桶标记为旧桶,
----1)查找操作,先看对应桶是否已经迁移没有迁移查旧桶,然后把对应桶数据迁移过去,迁移次数-1,如果迁移次数为0,就表示整个哈希表完成了迁移

更新、删除操作类似,先看是否完成迁移,没有迁移,先在旧桶完成迁移,再到新桶进行相应操作。

写文不易,给个点赞关注吧哈哈

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值