Go语言map的相关分析 | 青训营笔记

69 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

今天是2023年1月18日,今天青训营没有课程任务,所以今天尝试使用Go语言刷leetCode题目,从永恒经典的两数之和开始。

Map

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

func twoSum(nums []int, target int) []int {
    maps:=make(map[int]int,0)
    for k,v :=range nums{
        if value,ok:=maps[target-v];ok{
            return []int{k,value};
        }
        maps[v]=k;
    }
    return nil;
}

通过这道永恒经典的题目我们熟悉一下Go语言的一些简单语法,首先这里有个很奇怪的地方。 maps:=make(map[int]int,0) 这个创建map是通过make来创建,然后还有一种方式maps:=map[int]int{}这种方式,我通过第二种方式创建map,执行代码的时间是8ms,如果用第一种方式创建map,执行时间只有0ms,我猜测是不是第一种方式比第二种方式效率高,因此我使用IDE来写代码测试一下。但是测试的结果是有差距,但我觉得更多的是语言本身在运行的时候造成的时间误差,多次执行,有时候第一种快,有时候第二种快。所以我已经糊涂了,暂且只能归于leetcode的时间监控有问题。

然后在查资料的过程中,我了解到一些问题。

1.map和切片效率比较

map虽然key直接查找的效率很快,但是还是比切片慢100倍(莫名其妙的数字),估计的原因可能是哈希冲突,还有哈希映射本身存在的消耗,但是貌似只有数据量小的时候切片比map快

2.map的删除方式效率比较

1、在map的数量级在10w以内的话,make方式会比delete方式速度更快,但是内存会消耗更多一点。 2、如果map数量级大于10w的话,delete的速度会更快,且内存消耗更少。 3、对于不再使用的map,直接使用make方式,长度为0清空更快。

3.源码分析

因为我是Java转Go语言,所以很好奇再Go语言的map是如何设计的,我们都知道再java的hashmap再jdk1.8引入红黑树,让整个map的效率更上一层楼。 因此我想要探索一下这个Go语言的map,但是go语言的map有个问题是,它因为是程序本身定义的关键字,所以我没法通过鼠标悬浮然后跳转源码。因此我只能够下载Go语言的源码,再去源码里寻找。

// Map contains Type fields specific to maps.
type Map struct {
   Key  *Type // Key type
   Elem *Type // Val (elem) type

   Bucket *Type // internal struct type representing a hash bucket
   Hmap   *Type // internal struct type representing the Hmap (map header object)
   Hiter  *Type // internal struct type representing hash iterator state
}

go/src/cmd/compile/internal/types/type.go文件里面,我们可以找到上面这串代码,通过这个定义了Map这个结构体,然后这个结构体里面有一些属性,其中,key和elem是键和值,因为map可以处理各种类型的数据,因此都是Type类型的属性。

Bucket 是哈希桶, Hmap 表征了 map 底层使用的 HashTable 的元信息, 如当前 HashTable 中含有的元素数据、桶指针等, Hiter 是用于遍历 go map 的数据结构。