在Go语言中,HashMap被定义为一种无序容器(即不按顺序存储元素的数据结构),其中存储的元素是以 key-value 形式保存的,使用 key 来进行访问。可以通过哈希算法将 key 映射为一个索引,然后存储在桶(bucket)中,以便在后续查找时进行快速访问。
定义
type node struct {
key string // 键
value interface{} // 值
next *node // 链表指针
}
type hashMap struct {
buckets []*node // 桶
size int // 元素个数
}
New
// 创建一个新的HashMap
// 参数:
// 无
// 返回值:
// *hashMap: 新创建的HashMap
func New() *hashMap {
return &hashMap{
buckets: make([]*node, 16),
size: 0,
}
}
常用方法
Set
// 存储一个键值对到HashMap
// 参数:
// key: 键
// value: 值
// 返回值:
// 无
func (m *hashMap) Set(key string, value interface{}) {
index := hash(key) // 计算桶索引
if m.buckets[index] == nil {
m.buckets[index] = &node{key: key, value: value}
m.size++
} else {
// 遍历链表,查找 key 是否存在
current := m.buckets[index]
for current != nil {
if current.key == key {
current.value = value // 如果 key 存在,更新 value
return
}
current = current.next
}
// 如果 key 不存在,则在链表末尾添加一个新的节点
newNode := node{key: key, value: value}
newNode.next = m.buckets[index] // 原链表作为新节点的 next
m.buckets[index] = &newNode // 新节点作为头节点
m.size++
}
}
Get
// 从HashMap中获取一个值,根据键查找
// 参数:
// key: 键
// 返回值:
// interface{}: 查找到的值
// bool: 是否存在该键
func (m *hashMap) Get(key string) (interface{}, bool) {
index := hash(key) // 计算桶索引
current := m.buckets[index]
for current != nil {
if current.key == key {
return current.value, true // 返回找到的值和 true
}
current = current.next
}
return nil, false // 没找到,返回 nil 和 false
}
Remove
// 从HashMap中移除一个键值对
// 参数:
// key: 键
// 返回值:
// 无
func (m *hashMap) Remove(key string) {
index := hash(key) // 计算桶索引
current := m.buckets[index]
var prev *node
for current != nil {
if current.key == key {
if prev != nil {
prev.next = current.next // 修改前一个节点的指针
} else {
m.buckets[index] = current.next // 首节点被删除,修改 bucket 头指针
}
m.size--
return
}
prev = current
current = current.next
}
}
hash
// 这个方法是实现一个哈希函数,将字符串映射为一个0到15的整数,可以用来将字符串存储在散列表中,便于快速查找。具体原理如下:
//
//首先将哈希值h初始化为0,然后遍历字符串的每一个字符(使用for循环)。
//对于每一个字符,将哈希值左移5位(h<<5),相当于将h乘以2的5次方,然后将哈希值右移27位(h>>27),相当于将h除以2的27次方,这样可以保证哈希函数分布均匀。然后将结果与字符的ASCII码相加,得到新的哈希值。
//最后我们希望将哈希值变为0到15的整数,所以使用模运算(%16)将哈希值映射到0到15的范围内。
//综合以上三个步骤,得到的就是字符串的哈希值,能够实现高效的散列表存储、查找操作。
func hash(key string) uint32 {
h := 0
for i := 0; i < len(key); i++ {
h = (h << 5) | (h >> 27)
h += int(key[i])
}
return h % 16
}