GO高阶 の map详解



一. map 基础操作

map 的声明

    m := make(map[string]int, 2)
	m["hah"] = 15
	m["mmm"] = 20
	m["wwm"] = 30
	m["wsegewwm"] = 40
	fmt.Println(m)
    m := map[string]int{}
	m["hah"] = 15
	m["mmm"] = 20
	m["wwm"] = 30
	m["wsegewwm"] = 40
	fmt.Println(m)

输出 map 中的键值对的个数
len 中输出的是键值对的个数,而不是容量的个数。

	a := map[string]int{"15": 15, "16": 16, "17": 17, "18": 18, "19": 19}
	fmt.Println(a)
	fmt.Println(len(a))

删除某个 key

	a := make(map[string]int, 5)
	a["王"] = 12
	fmt.Println(a)
	delete(a, "王")
	fmt.Println(a)

查看 key

    for k, v := range a { // 同时查看 key ,value
		fmt.Println(k, v)
	}
	
	for k := range a { // 只查看 key
		fmt.Println(k)
	}

前提:键不重复,可哈希

v1=make(map[int]int)
v2=make(map[string]int)
v3=make(map[[2]int]int)
v6=make(map[bool]int)
v4=make(map[[]int]int) // 不行,可以是数组,但不能是切片
v5=make(map[[2][]int]int) //会报错
v5=make(map[[2]map[string]string]int) //会报错




二.原理

1.1 hash的基本存储原理

拉模 + 拉链法 来快速了解 hash 表的存储原理

在这里插入图片描述

这是 Python 或者 go 中,对 map 这种存储类型的基本原理,但是每种语言中,针对自己的语言特点,都进行了进一步的优化。




1.2 Map的整体存储结构

其核心是由 hmapbmap 两个结构体实现的。

在这里插入图片描述

1.2.1 初始化

// 初始化一个可容纳 10 个元素的map
info=make(map[string]string,10)
  • 第一步:创建一个 hmap 结构体对象
  • 第二步:生成一个哈希因子hash0 并赋值到 hmap 对象中(用于后续为 key 创建哈希值)。
  • 第三步:根据 hint=10 ,并根据算法规则来建立 B ,当前 B 应该为 1.
hintB
0-80
9~131
14~262
  • 第四步:根据 B 去创建桶(bmap对象),并存放在 buckets 数组中,当前的 bmap 的数量应该为 2
    • B<4 时,根据 B 创建桶的个数的规则为:2B(标准桶)
    • B>=4 时,根据 B 创建桶的个数的规则为 :2B+2B-1 (标准桶 + 溢出桶)
    • 注意: 每个 bmap 中可以存储 8 个键值对,当不够存储时,需要使用溢出桶,并将当前 bmap 中的 overflow 字段指向溢出桶的位置。



1.2.2 写入数据

  1. 结合哈希因子和键 name 生成哈希值
  2. 获得哈希值的 后B位,并决定该值放在哪个桶中
  3. 上一步确定以后,接下来就在桶中写入数据

获取哈希值得 tophash (哈希值的高八位) 将 tophash、key、value 分别写入桶的三个数组中,如果桶已经满了,则通过 voerflow 找到溢出桶,并在溢出桶中继续写入。
注意:以后在桶中查找数据时,会基于 tophash 来找(tophash相同则再去比较key)

  • 第四步:hmap 的个数 count++ map中的元素+1



1.3 map 的扩容

  • map 中数据总个数/桶个数 > 6.5,引发翻倍扩容
  • 使用了太多的溢出桶 (溢出桶太多,会导致map处理速度降低)
    • B<=15 ,已使用的溢出桶个数 >=2B,时,引发等量扩容
    • B>15,已使用的溢出桶的个数 >=215,引发等量扩容

在这里插入图片描述




1.4 迁移

  1. 如果是翻倍扩容的话,迁移规则就是将旧桶中的数据分流到两个桶中(比例不一样),并且桶编号的位置为:同编号位置 和 翻倍后对应的编号位置。

在这里插入图片描述

  1. 等量扩容的话,溢出桶太多引发的扩容,那么数据迁移机制就会比较简单,就是将旧桶中的值迁移到新桶中,这种迁移的目的就在于让数据更紧凑,从而减少溢出桶。


参考文献

  1. https://www.cnblogs.com/maji233/p/11070853.html
  2. https://www.bilibili.com/video/BV1Nr4y1w7aa?p=10&share_source=copy_web
posted @ 2021-06-29 21:01  沧海一声笑rush  阅读(151)  评论(0编辑  收藏  举报