go语言中hashmap底层分析

1. hashmap 的基本方案

通常在学习hashmap 数据结构,会遇到两种方法实现,分别是开放寻址法和拉链法。下面介绍一个这两种方法的区别。

1.1 开放寻址法

  1. 假设在map中已经存在三个节点,现在插入第四个节点信息,初始状态如下:
    在这里插入图片描述
  2. 先通过hash函数计算,然后对其进行取模(根据map 大小长度),如果计算出来的位置已经有其他信息占据,则会往后移动直到找到空位置。
    在这里插入图片描述

1.2 拉链法

  1. 假设hashmap中已经存在一个节点,现在继续往里面加入一个,初始信息如下:
    在这里插入图片描述
  2. 通过hashi计算,如果计算出来的位置上已经存在其他信息,则是通过链表的形式往下加入
    在这里插入图片描述

拉链法的几个专有名词
在这里插入图片描述

2. go中的map

2.1 源码位置

runtime/map.go中,如图:
在这里插入图片描述

2.2 数据结构示意图

在这里插入图片描述

2.3 bucket 数据结构

在这里插入图片描述

3. map 的初始化

3.1 通过make 初始化

  1. code
func main() {
	m := make(map[string]int, 10)
	fmt.Println(m)
}
  1. 通过命令,汇编分析go build -gcflags -S main.go
  2. 汇编代码
main.go:6) LEAQ type.map[string]int(SB), AX
main.go:6) MOVQ AX, (SP)
main.go:6) MOVQ $10, 8(SP)
main.go:6) MOVQ $0, 16(SP)
main.go:6) PCDATA $1, $0
main.go:6) CALL runtime.makemap(SB)
main.go:6) MOVQ 24(SP), AX
  1. 通过汇编能发现map调用的是runtime/map.go 包下的makemap 方法
func makemap(t *maptype, hint int, h *hmap) *hmap {
	mem, overflow := math.MulUintptr(uintptr(hint), t.bucket.size)
	if overflow || mem > maxAlloc {
		hint = 0
	}

	// initialize Hmap
	if h == nil {
		h = new(hmap)
	}
	h.hash0 = fastrand()

	// Find the size parameter B which will hold the requested # of elements.
	// For hint < 0 overLoadFactor returns false since hint < bucketCnt.
	B := uint8(0)
	for overLoadFactor(hint, B) {
		B++
	}
	h.B = B

	// allocate initial hash table
	// if B == 0, the buckets field is allocated lazily later (in mapassign)
	// If hint is large zeroing this memory could take a while.
	if h.B != 0 {
		var nextOverflow *bmap
		h.buckets, nextOverflow = makeBucketArray(t, h.B, nil)
		if nextOverflow != nil {
			h.extra = new(mapextra)
			h.extra.nextOverflow = nextOverflow
		}
	}

	return h
}
  1. 上述方法结构示意图如下:
    在这里插入图片描述

3.2 通过字面量初始化

3.2.1 元素小于25个时,内部转化为简单赋值

1) code

func main() {
	h := map[string]int{
	"1": 2,
	"2": 2,
	"3": 3,
	}
}

2)汇编代码底层其实是这样子的

func main() {
	h := make(map[string]int, 3)
	h["1"] = 1
	h["2"] = 2
	h["3"] = 3
}
3.2.2 元素多于25个,转换为循环赋值

1)code

func main() {
	h := map[string]int{
	"1": 2,
	"2": 2,
	"3": 3,
	...
	"26" : 26
	}
}

2)实际上
在这里插入图片描述

4 map 的访问

  1. 步骤1
    在这里插入图片描述
  2. 计算桶号
    在这里插入图片描述
  3. 计算tophash
    在这里插入图片描述
  4. 匹配

5. map 写入

在这里插入图片描述

总结

  1. go 语言中使用拉链法实现了hashmap
  2. 每一个桶中存储键哈希的前8位
  3. 桶超出8个数据,就会存储到溢出桶中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值