开发者

Golang HashMap实现原理解析

目录

    Golang HashMap实现原理解析

    Golang HashMap实现原理解析

    • HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作。其核心原理如下:
      • 哈希函数:将键转换为数组索引。理想情况下,不同键应映射到不同索引,但冲突难以避免。
      • 数组+链表:使用数组作为桶(Bucket),每个桶是一个链表,解决哈希冲突(链地址法)。
      • 动态扩容:当元素数量超过容量与负载因子的乘积时,扩容并重新分配元素,保持操作高效性。
    package main
    import "fmt"
    // Entry 键值对链表节点
    type Entry struct {
        Key   string
        Value interface{}
        Next  *Entry
    }
    // HashMap 哈希表结构
    type HashMap struct {
        buckets    []*Entry // 桶数组
        capacity   int      // 初始容量
        size       int      // 元素数量
        loadFactor float64  // 负载因子
    }
    // NewHashMap 初始化哈希表
    func NewHashMap(capacity int) *HashMap {
        return &HashMap{
            buckets:    make([]*Entry, capacity),
            capacity:   capacity,
            loadFactor: 0.75,
        }
    }
    // hash 哈希函数(FNV-1a算法)
    func (h *HashMap) hash(key string) int {
        const (
            offset = 2166136261
            prime  = 16777619
        )
        hash := offset
        for _, c := range key {
            hash ^= int(c)
            hash *= prime
        }
        return hash
    }
    // getIndex 计算键对应的桶索引
    func (h *HashMap) getIndex(key string) int {
        return h.hash(key) % h.capacity
    }
    // Put 插入键值对
    func (h *HashMap) Put(key string, value interface{}) {
        if float64(h.size)/float64(h.capacity) >= jsh.loadFactor {
            h.resize()
        }
        index := h.getIndex(key)
        entry := h.bucZvFuRkets[index]
        // 遍历链表查找键是否存在
        for entry != nil {
            if entry.Key == key {
                entry.Value = value // 存在则更新
                return
            }
            entry = entry.Next
        }
        // 不存在则插入链表头部
        h.buckets[index] = &Entry{
            Key:   key,
            Value: value,
            Next:  h.buckets[index],
        }
        h.size++
    }
    // Get 获取值
    func (h *HashMap) Get(key string) (interface{}, bool) {
        index := h.getIndex(key)
        entry := h.buckets[index]
        for entry != nil {
            if entry.Key == key {
                return entry.Value, t编程rue
            }
            entry = entry.Next
        }
        return nil, false
    }
    // Delete 删除键
    func (h *HashMap) Delete(key string) bool {
        index := h.getIndex(key)
        entry := h.buckets[index]
        var prpythonev *Entry
        for entry != nil {
            if entry.Key == key {
                if prev == nil {
                    h.buckets[index] = entry.Next // 删除头节点
                } else {
                    prev.Next = entry.Next // 中间或尾部节点
                }
         编程       h.size--
                return true
            }
            prev = entry
            entry = entry.Next
        }
        return false
    }
    // resize 扩容哈希表
    func (h *HashMap) resize() {
        newCapacity := h.capacity * 2
        newBuckets := make([]*Entry, newCapacity)
        for i := 0; i < h.capacity; i++ {
            entry := h.buckets[i]
            for entry != nil {
                next := entry.Next
                newIndex := h.hash(entry.Key) % newCapacity // 重新计算索引
                entry.Next = newBuckets[newIndex]          // 插入新桶头部
                newBuckets[newIndex] = entry
                entry = next
            }
        }
        h.buckets = newBuckets
        h.capacity = newCapacity
    }
    func main() {
        hm := NewHashMap(2) // 初始容量设为2便于触发扩容
        hm.Put("name", "Alice")
        hm.Put("age", 30)
        hm.Put("lang", "Go") // 触发扩容
        if val, ok := hm.Get("name"); ok {
            fmt.Println("name:", val) // 输出 Alice
        }
        hm.Delete("age")
        if _, ok := hm.Get("age"); !ok {
            fmt.Println("age deleted") // 输出此句
        }
    }

    到此这篇关于golang HashMap实现原理的文章就介绍到这了,更多相关goland hashmap原理内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:没有了

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜