map:建立事物关联的容器。map使用散列表(hash)实现
映射关系容器使用两种算法L:散列表和平衡树
散列表:可看成是一个数组(又称‘桶’),数组的每一个元素是一个列表。
根据散列函数获得每个元素的特征值,将特征值作为映射的键。
若特征值重复,表示元素发生碰撞并碰撞的元素放在同一个特征值的列表中进行保存。
散列表查找的时间复杂度为O(1),和数组一致;最坏情况为O(n)。
散列表需要尽量避免元素发生碰撞以提高查找效率,这样就对桶进行扩容,每次扩容都需要将元素重新放入到桶中。
平衡树:类似于油浮子关系的数据树,每个元素放入树时,都要与一些节点进行比较。
平衡树的时间复杂度为O(log n)。
map定义:
map[KeyType] ValueType
map 【键类型】键对应的值类型
例子:
package main
import(
"fmt"
)
func main(){
//map是一个内部实现的类型,需要make创建。若不创建使用map类型,会触发宕机(死机)错误。
//声明变量scene并初始化
scene := make(map [string] int)
/*
可拆分为:
var scene map[string] int
scene = make(map [string] int)
*/
//给键值,向map中加入映射关系
scene["route1"] = 66
//查找map值
fmt.Println(scene["route1"])
//尝试查找不存在的键,返回ValueType的默认值0
v := scene["route2"]
fmt.Println(v)
}
某些情况下,需要明确知道某个键是否在map中存在,可以使用一种特殊的写法来实现。
v:ok := scene ["rounte"]
在默认获取关键值的基础上,多取一个变量ok,可以判断route是否存在于map中。
map的for range遍历:
func main(){
//声明map
scene := make(map[string] int )
scene["route"] = 1
scene["black"] = 2
scene["red"] = 3
//循环遍历map
for key,value := range scene{
fmt.Println(key,value)
}
}
若只遍历值:
for _,vakue := range scene{}
若只遍历键值:
for key := range scene{}
例:遍历+排序
package main
import (
"fmt"
"sort"//导入sort包,调用后续的Strings方法
)
func main(){
scene := make(map [string] int)
scene["xiaosu"] = 123
scene["xiaoli"] = 456
scene["xiaozhang"] = 789
//声明切片,保存map数据
var sceneList []string
//将map遍历的元素复制到切片中
for value := range scene{
sceneList = append(sceneList,value)
}
//给切片排序,传递的是地址
sort.Strings(sceneList)
fmt.Println(sceneList)
}
使用delete()函数从map中删除键值对
格式:delete(map,键)
func main() {
scene := make(map[string]int)
scene["xiaosu"] = 123
scene["xiaoli"] = 456
scene["xiaozhang"] = 789
delete(scene, "xiaosu")
//声明切片,保存map数据
var sceneList []string
//将map遍历的元素复制到切片中
for value := range scene {
sceneList = append(sceneList, value)
}
//给切片排序,传递的是地址
sort.Strings(sceneList)
fmt.Println(sceneList)
}
清空map中所有元素:
Go语言没有问map提供任何清空所有元素的函数,方法。清空map的唯一方法是重新make一个新的map,由于Go采用并行垃圾回收效率比一个清空函数高效。
能够在并发环境中使用map——sync.Map
例1和例2的对比:
package main
func main() {
scene := make(map[int]int)
go func() {
for {
scene[1] = 1
}
}()
go func() {
for {
_ = scene[1]
}
}()
for {
}
}
输出错误:fatal error: concurrent map read and map write
原因:并发的map读写,两个并发函数不断地对map进行状态竞争,正常情况下解决办法是加锁,但效率低下。
Go1.9版本提供sync.Map来处理。
sync.Map特性:
- 无需初始化,直接声明
- sync.Map不能使用map方式进行取值和设置等操作,而是使用sync.Map的方法进行调用。Store表示存储,Load表示获取,Delete表示删除。
- 使用range配合一个回调函数进行遍历操作,通过回调函数的返回内部遍历出来的值
package main
import (
"fmt"
"sync"
)
func main() {
//声明 scene,类型是sync.Map
var scene sync.Map
//保存值到sync.Map中
scene.Store("xiaosu", 111)
scene.Store("xiaoli", 222)
scene.Store("xiaohu", 333)
//查找对应的值
fmt.Println(scene.Load("xiaosu"))
//删除键值对
scene.Delete("xiaosu")
//Range()方法可以遍历sync.Map,需要提供一个匿名函数,参数是key,value,类型是interface{}
//Range()每次遍历一个一个元素,都会调用匿名函数将值返回
scene.Range(func(key, value interface{}) bool {
fmt.Println("iterate:", key, value)
return true
})
}
输出:
100 true
iterate:xiaoli 222
iterate:xiaohu 333