MAP
map的数据结构
hash表+bucket桶
参考连接:
phati-sawant.medium.com/internals-o…
phati-sawant.medium.com/internals-o…
创建map是为了查找的时候时间复杂度为O(1)
这个是利用hash来实现的
在golang中的map可以理解为bucket的集合
具体理解是这样的
m:=make(map[string]string)
make之后返回的是一个map的头部信息的指针,所以当map不建立的时候才会为nil
这个 头部主要包括以下的内容
- map中entries的数目
- bucket的数目(log(bucket))
- 指向bucket array的指针(这个是重点)
- hash seed:用来创建不同的map
如下图所示~
接下来就是重头戏★,°:.☆( ̄▽ ̄)/$: .°★ 。
我们要开始讲解bucket的内容了
bucket实际上存储了key value,不过最多只可以存储8个键值对~
那如果超过8个又在桶里的范围内,那该怎么办呢?
当然是在bucket的后面增加了一个指针(旧桶溢出),指针指向新的bucket
举例子
m["green"]=1
首先会使用hash function,产生hash code。接下来,找到对应的bucket,然后存进去。
如果没有的话,存入新的;如果溢出,新建一个bucket,把内容存入,并且overflow pointer将指向新的bucket
map遍历
map的遍历时随机的,有人说时seed()的原因,也有说hash bucket指向新桶的原因,没有理解~
package main
import "fmt"
func main() {
m := make(map[int]int)
for i := 0; i < 10; i++ {
m[i] = i
}
for _, v := range m {
fmt.Print(v)
}
fmt.Println()
}
当map增长的时候
当bucket里面的元素,达到load factor为6.5(一定程度),那么就进行增加,具体是增加bucket的数量,为原来的2被。
并且将bucket的值,由原来的复制到了新的bucket里面。这个复制的过程不是一次性完成的,而是慢慢推移的。
在复制的过程中,map会维护一个指针,让新桶指向旧桶
删除map中的元素
map中的bucket的数量,只能增长,不能删除。所以哪怕我们删除掉map中的所有元素,map中bucket的数量也是不变的。
Qusetion:
-
增加元素:
如果插入一个新元素,对应的bucket有位置,就增加;没有位置的话,就新建一个bucket,旧bucket的overflow pointer指向新的bucket。并将元素插入到新的bucket里面
如果这时候元素达到一定的限制,会进行桶的扩充,map将新建bucket,数量为原来old bucket的数目的两倍。然后将旧桶中的数据复制到新桶中,这个数据的复制过程不是一次性的,是慢慢推进的
结论
本篇,没有详细的讲解map,但是从宏观上看map已经足够
具体总结为以下几点:
- map 实际上是 array of buckets
- map的查找时间是O(1)
- 当遍历map的时候,可以修改它
- map遍历的时候是随机的
- bucket的数量一直都是翻倍
- 溢出指针也就是overflow pointer一定是指向一个新的桶,当桶满并且接收到新的值。