【Go实战基础】最常用的高效数据结构 map
目录
一、简介
二、数据结构
三、实战
1、创建 g004.go
2、编译和运行
3、运行结果
一、简介
实际编程开发中,在任何语言里面,除了数组之外,最常用的数据结构莫就是映射 map。map是一种数据结构,在很多语言里面都内置了map类型,可以看作是键值对的映射,例如:
a => 18b => 20c => 25
Go 的 Map 底层是一个 hash 表,表面上看 Map 只有键值对结构,实际上在存储的过程中涉及了数组和链表,之所以高效是因为其集合了顺序存储和链式存储两种存储结构。数组是 HashMap 的主干,数组的每个元素关联了一个链表。
二、数据结构
在源码中,Go 表示 map 的结构体是 hmap,它是 hashmap 的“缩写”,其结构如下:
// Go hmap 结构type hmap struct { // 元素个数,调用 len(map) 时,直接返回此值 count int // 标记读写状态,避免并发读写 flags uint8 // 扩容常量, 可以容纳 2 ^ B 个bucket B uint8 // 溢出的 的 bucket 近似数 noverflow uint16 // hash种子 计算 key 的哈希的时候会传入哈希函数 hash0 uint32 // 指向 buckets 数组指针,大小为 2^B // 如果元素个数为0,就为 nil buckets unsafe.Pointer // 扩容的时候,用于复制的 buckets 数组 oldbuckets unsafe.Pointer // 扩容时已迁移的个数,小于此地址的 buckets 迁移完成 nevacuate uintptr // 记录溢出相关 extra *mapextra // optional fields}// 溢出指针type mapextra struct { // overflow 包含的是 hmap.buckets 的 overflow 的 bucket overflow *[]*bmap // oldoverflow 包含扩容时的 hmap.oldbuckets 的 overflow 的 bucket oldoverflow *[]*bmap // 指向空闲的 overflow bucket 的指针 nextOverflow *bmap}// 桶type bmap struct { // 记录着每个key的高8个bits tophash [bucketCnt]uint8 }
每个 map 的底层结构是 hmap,是有若干个结构为 bmap 的 bucket 组成的数组,每个 bucket 可以存放若干个元素(通常是 8 个),当一个bucket中的元素超过 8 个的时候,hmap 会使用 extra 中的overflow来扩展存储key。
三、菜鸟实战
实战需求: Map 的基础操作
马上安排!
1、创建 g004.go
/* * @Author: 菜鸟实战 * @FilePath: /go110/go-004/g004.go * @Description: map 实战 */package mainimport ("fmt""runtime")func mapTest() {}// 主函数func main() {// 使用内置函数打印println("Hello", "菜鸟实战")// 先声明 map,再赋值var m1 map[string]stringm1 = make(map[string]string)m1["a1"] = "1"m1["b1"] = "2"// 直接创建,然后赋值m2 := make(map[string]string)m2["a2"] = "3"m2["b2"] = "4"// 初始化赋值一体化m3 := map[string]string{"a3": "5","b3": "6",}fmt.Println("## m3 信息: ")fmt.Println(m3)// 查找键值是否存在fmt.Println("## 检查 m2 是否存在 a2 : ")if v, ok := m2["a2"]; ok {fmt.Println(v)} else {fmt.Println("键值不存在")}// 遍历 mapfmt.Println("## 遍历 m1 : ")for k, v := range m1 {fmt.Printf("%v => %v \n", k, v)}// 使用包函数打印fmt.Printf("版本: %s \n", runtime.Version())}
2、编译和运行
# 1、生成模块依赖
go mod init g004
# 2、编译
go build g004.go
# 3、编译后的目录结构
└── go-004
├── g004
├── g004.go
└── go.mod
# 4、运行
go run g004
3、运行结果
Hello 菜鸟实战
## m3 信息:
map[a3:5 b3:6]
## 检查 m2 是否存在 a2 :
3
## 遍历 m1 :
a1 => 1
b1 => 2
版本: go1.17.10
菜鸟实战,持续学习!