> 文档中心 > 【Go实战基础】最常用的高效数据结构 map

【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 

菜鸟实战,持续学习!