Golang map

Golang map

map是什么?

map就是一个kv键值对的集合,可以根据key在o(1)的时间复杂度内取到value。在Golang中map的底层实现,是使用的类似拉链法的方法解决hash冲突的。

什么是hash冲突?

hash表的原理是将多个kv键值对散列的存储到buckets中,buckets是一个连续的数组。存储kv值需要计算hash值和计算索引位置。

1.计算hash值。根据hash函数将key转化为一个hash值。
2.计算索引位置。利用hash值对,桶的数量,取模得到一个索引值,这样就找到了位置。

不妨思考一下,如果我们得到的hash值相同,那么计算得到的hash位置必定相同,这就造成了哈希冲突,这个需要怎么解决?

1.拉链法。
2.开放寻址法。

拉链法

拉链法是一种常见的解决哈希冲突的方法,拉链法主要实现是底层不直接使用连续数组来直接存储数据元素,而是通过数组和链表组合使用,数组里存储一个指针,指向一个链表。如果链表过长,也可以使用优化策略,比如用红黑树代替链表。

在这里插入图片描述

开放寻址法

开发地址法与拉链法不同,开发地址法是将具体的数据元素存储在数组桶中,在要插入新元素是,先根据哈希函数算出哈希值,根据哈希值计算索引,如果发现冲突了,就从计算出的索引位置向后探测,直到找到未使用的数据槽为止。

在这里插入图片描述

map的底层实现原理?

map的底层实现数据结构实际上就是一个hash表。在运行时表现为指向hmap结构的指针,hmap中记录了桶数组指针,溢出桶指针以及元素个数等字段。每个桶是一个bmap的数据结构体,可以存储8个kv和8个tophash以及指向下一个溢出桶的指针。为了内存紧凑,采用的是先存8个key后再存value。

map的内存模型

表示map的其实就是hmap结构体:

type hmap struct {
   
	count     int // # 返回的就是 len(map)
	flags     uint8
	B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	noverflow uint16 // 溢出桶的bucket近似数
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

	extra *mapextra // optional fields
}

B 确定了hmap有2^B次方个桶,每个桶里面都是一个bmap,bmap在编译期间是动态创建的一个新结构:

type bmap struct {
   
    topbits  [8]uint8
    keys     [8]keytype
    values   [8]valuetype
    pad      uintptr
    overflow uintptr
}

所以,bmap就是我们说的桶。一个桶里面最多可以装8个kv键值对,这些key之所以会在一个桶内,是因为他们经过哈希计算之后,哈希结果是’一类’的。在桶内,会根据hash值高8位决定key放到那个桶内的某个位置上(一个桶8个位置)。

在hmap中有一个extra *mapetra的字段,这个字段的作用是为了防止GC扫描时把溢出桶也处理了,保证GC的扫描性能。
为什么呢?这主要与map的类型有关,如果map的kv是值类型,那么就不用考虑GC扫描,如果是指针类型或着是需要GC扫描的类型,都需要放在extra里面,防止被扫描。

具体的map底层原理图:
在这里插入图片描述

对于map查找kv键值对的时候,我是这样理解的:map 底层是一个 hmap 结构,hmap 包含一个 buckets 指针,它指向一个由多个 bmap 组成的数组。哈希值的低 B 位决定使用哪个 bmap,然后根据高位哈希值在该 bmap 内查找具体的键值对。

map赋值原理

1.在对map进行赋值操作的时候,map一定要先进行初始化,否则panic。

	var m map[int]int
	m[1]=1

2.map不是线程安全的,不支持并发读写操作。

func main() {
   
	m := map
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值