Map

123 阅读3分钟

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

这个 头部主要包括以下的内容

  1. map中entries的数目
  2. bucket的数目(log(bucket))
  3. 指向bucket array的指针(这个是重点)
  4. hash seed:用来创建不同的map

image-20220425193614666

如下图所示~

接下来就是重头戏★,°:.☆( ̄▽ ̄)/$: .°★

我们要开始讲解bucket的内容了

bucket实际上存储了key value,不过最多只可以存储8个键值对~

那如果超过8个又在桶里的范围内,那该怎么办呢?

当然是在bucket的后面增加了一个指针(旧桶溢出),指针指向新的bucket

image-20220425194045711

举例子

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:

  1. 增加元素:

    如果插入一个新元素,对应的bucket有位置,就增加;没有位置的话,就新建一个bucket,旧bucket的overflow pointer指向新的bucket。并将元素插入到新的bucket里面

    如果这时候元素达到一定的限制,会进行桶的扩充,map将新建bucket,数量为原来old bucket的数目的两倍。然后将旧桶中的数据复制到新桶中,这个数据的复制过程不是一次性的,是慢慢推进的

结论

本篇,没有详细的讲解map,但是从宏观上看map已经足够

具体总结为以下几点:

  1. map 实际上是 array of buckets
  2. map的查找时间是O(1)
  3. 当遍历map的时候,可以修改它
  4. map遍历的时候是随机的
  5. bucket的数量一直都是翻倍
  6. 溢出指针也就是overflow pointer一定是指向一个新的桶,当桶满并且接收到新的值。