Hashmap

栏目: Java · 发布时间: 5年前

内容简介:由于go语言是一个强类型的语言,因此hashmap也是有类型的,具体体现在key和value都必须指定类型,比如声明一个key为string,value也是string的map,需要这样做大部分类型都能做key,某些类型是不能的,共同的特点是:

基本语法

定义hashmap变量

由于 go 语言是一个强类型的语言,因此hashmap也是有类型的,具体体现在key和value都必须指定类型,比如声明一个key为string,value也是string的map,

需要这样做

var m map[string]string // 声明一个hashmap,还不能直接使用,必须使用make来初始化
m = make(map[string]string) // 初始化一个map
m = make(map[string]string, 3) // 初始化一个map并附带一个可选的初始bucket(非准确值,只是有提示意义)

m := map[string]string{} // 声明并初始化

m := make(map[string]string) // 使用make来初始化

大部分类型都能做key,某些类型是不能的,共同的特点是: 不能使用== 来比较,包括: slice, map, function

get,set,delete

m := map[string]int
m["a"] = 1

fmt.Println(m["a"]) // 输出 1

// 如果访问一个不存在的key,返回类型默认值
fmt.Println(m["b"]) // 输出0

// 测试key是否存在
v, ok := m["b"]
if ok {
    ...
}

// 删除一个key
delete(m, "a")

迭代器

// 只迭代key
for k := range m {
    ...
}

// 同时迭代key-value
for k, v := range m {
    ...
}

在迭代的过程中是可以对map进行删除和更新操作的,规则如下:

  • 迭代是无序的,跟插入是的顺序无关
  • 迭代的过程中删除一个key,无论遍历还是没有遍历过都不会再遍历到
  • 迭代的过程中添加一个key,不确定是否能遍历到
  • 未初始化的map也可以迭代

其他

  • map的value是不可取地址的,意味着 &m["a"]这样的语法是非法的
  • len可以获取当前map的kv个数

内部结构

hashmap结构

golang的map是hash结构的,意味着平均访问时间是O(1)的。同传统的hashmap一样,由一个个bucket组成:

// A header for a Go map.
type hmap struct {
 // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
 // ../reflect/type.go.  Don't change this structure without also changing that code!
 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)
 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)

 // If both key and value do not contain pointers and are inline, then we mark bucket
 // type as containing no pointers. This avoids scanning such maps.
 // However, bmap.overflow is a pointer. In order to keep overflow buckets
 // alive, we store pointers to all overflow buckets in hmap.overflow.
 // Overflow is used only if key and value do not contain pointers.
 // overflow[0] contains overflow buckets for hmap.buckets.
 // overflow[1] contains overflow buckets for hmap.oldbuckets.
 // The first indirection allows us to reduce static size of hmap.
 // The second indirection allows to store a pointer to the slice in hiter.
 overflow *[2]*[]*bmap
}

bucket内部

// A bucket for a Go map.
type bmap struct {
 tophash [bucketCnt]uint8
 // Followed by bucketCnt keys and then bucketCnt values.
 // NOTE: packing all the keys together and then all the values together makes the
 // code a bit more complicated than alternating key/value/key/value/... but it allows
 // us to eliminate padding which would be needed for, e.g., map[int64]int8.
 // Followed by an overflow pointer.
}

根据一个key得到value

func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
  • *maptype为map的类型信息,是编译器在编译期静态生成的,里面包含了map的一些元信息,比如key和value的类型信息等等
  • *hmap为map的header,即map的引用
  • key是一个通用的指针,代表了key的引用
  • 返回值为一个指针,指向对应的value引用

hash计算找到bucket

那我们怎么访问到对应的bucket呢,我们需要得到对应key的hash值

alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))

根据tophash和key定位到具体的bucket

  • tophash可以快速试错,如果tophash不相等直接跳过
  • tophash相等的话,根据key的比较来判断是否相等,如果相等则找到
  • 如果当前bucket都试玩还没有找到,则调到下一个bucket

扩容

loadFactor %overflow bytes/entry hitprobe missprobe
4.00 2.13 20.77 3.00 4.00
4.50 4.05 17.30 3.25 4.50
5.00 6.85 14.77 3.50 5.00
5.50 10.55 12.94 3.75 5.50
6.00 15.27 11.67 4.00 6.00
6.50 20.90 10.79 4.25 6.50
7.00 27.14 10.15 4.50 7.00
7.50 34.03 9.73 4.75 7.50
8.00 41.10 9.40 5.00 8.00

各个参数的意思:

  • %overflow 溢出率,平均一个bucket有多少个kv的时候会溢出
  • bytes/entry 平均存一个kv需要额外存储多少字节的数据
  • hitprobe 找到一个存在的key平均需要找几下
  • missprobe 找到一个不存在的key平均需要找几下

目前采用的是这一行:

| 6.50 | 20.90 | 10.79 | 4.25 | 6.50 |


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Perl语言入门

Perl语言入门

[美] Randal L.Schwartz、Tom Phoenix / 李晓峰 / 中国电力出版社 / 2002-8 / 48.00元

本书第一版于1993年问世,并从此成为畅销书。本书由Perl社区最著名、最活跃的两位成员写成,是Perl程序设计语言的精髓指南。 Perl最初只是Unix系统管理员的一个工具,在工作日里被用在无数的小任务中。从那以后,它逐步发展成为一种全功能的程序设计语言,特别是在各种计算平台上,它被用作Web编程、数据库处理、XML处理以及系统管理——它能够完成所有这些工作,同时仍然是处理小的日常工作的完......一起来看看 《Perl语言入门》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具