环境
大纲 map特点map基本用法hash table 相关知识 一、map基础知识 map特点 map是哈希表的引用map需要初始化后使用由于map是引用类型,所以传递的成本很低,64位机器上占8字节,32位机器上占4字节map的key的类型必须是可使用==和!=比较的map的中存储的元素是无序的 map初始化 使用字面量,初始化并赋值go1.17.8 darwin/arm64
m := map[int]string{
1:"one",
2:"two",
}
使用make关键字
m := make(map[int]string)
m[1]="one"
m[2]="two"
map访问
遍历
m := map[int]string{
1:"one",
2:"two",
}
for k,v := range m{
fmt.Println(k,v)
}
查找key对应的value
m := map[int]string{
1:"one",
2:"two",
}
v1 := m[1]
v2 := m[2]
如果map中对应的key不存在,则返回零值。或者判断key是否存在:
m := map[int]string{
1:"one",
2:"two",
}
if v1, ok := m[1]; !ok {
fmt.Println("key 1 is not exist")
}
删除key
m := map[int]string{
1:"one",
2:"two",
}
delete(m, 1)
二、golang实现
go使用拉链法解决hash碰撞问题。扩容时不会立马迁移和释放原有空间,而是通过后续的访问逐步的将旧空间中的内容迁移到新空间,再由GC释放旧空间。
1.数据结构
hmap相当于map指向hash表的头指针:
// A header for a Go map.
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
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
}
count:map中的现有元素总数flags:缓存hash表的状态变量B:表示bucket的数量,bucket数量=2^Bnoverflow:计算溢出桶的数量hash0: hash函数的随机数种子,为hash函数添加随机性,map创建时确定buckets: 指向当前桶数组的第一个元素(桶数组的头指针)oldbuckets: 指向旧桶数组的第一个元素extra:指向溢出桶
// A bucket for a Go map.
type bmap struct {
tophash [bucketCnt]uint8
}
// compile internal struct
type bmap struct {
tophash [8]uint8
keys [8]keytype
values [8]valuetype
pad uintptr
overflow uintptr
}
tophash:存储计算出的hash的高8位值
2. 访问
当一个键值对需要插入或者访问时,首先要根据key键找到存储键的桶,在从桶中查找出相应槽位的key和value。这就涉及到如下三个问题:
如何确定是哪个buckettophash怎么确定为什么key和value通过地址偏移量访问golang中通过对key哈希后,取hash(key)的低B位来确定bucket的数组下标。通过hash(key)的高8位来与桶中槽位的tophash相比较从而确定应该存储或访问哪个槽位的数据。由于key和value是集中存储的(所有的key存一块儿,value存一块儿,有利于内存对齐),所以很容易通过地址的偏移量方位内存中相应的数据。图示如下:
总结(TODO) 参考资料
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)