map实现方式

版本:1.20 源码位置:src/runtime/map.go

数据结构:

  type hmap struct {

      count     int // 当前容量,len(m)返回值
       flags     uint8
          B         uint8  // 负载因子
          noverflow uint16 // 溢出,用于解决哈希冲突
        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

  }

  数据存放都是通过指针偏移方式计算得出

 

初始化:

  func reflect_makemap(t *maptype, cap int) *hmap {
    .....
    return makemap(t, cap, nil)
  }
  根据cap初始化B的大小

 

查找:

  根据key计算出哈希值,低位(根据B计算)代表外部所有桶位置,高位代表桶内部的位置

  高位相等,对比key

  搬迁过程优先从旧buckets中查找

插入: 

  根据key计算hash  

  找桶:bucket := hash & bucketMask(h.B); b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))

  遍历tophash找出桶里面的空位,bucketCnt=8

 

删除:

  查找

  找到后删除

  重新整理tophash

  PS:不会自动缩容

 

扩容:  

  负载因子=键数量/bucket数量,什么条件需要rehash

  2倍扩容方式,循序渐进赋值

  等量扩容

 

问题:

  为什么遍历返回结果是无序,因为startBucket是根据r随机计算得出

  // decide where to start
      var r uintptr
      if h.B > 31-bucketCntBits {
          r = uintptr(fastrand64())
      } else {
          r = uintptr(fastrand())
      }
      it.startBucket = r & bucketMask(h.B)
 
posted @ 2023-07-21 16:31  零下¥六度  阅读(6)  评论(0编辑  收藏  举报