- HashMap是一種基于哈希表實現的鍵值對存儲結構,它通過哈希函數將鍵映射到數組的索引位置,支持高效的插入、查找和刪除操作。其核心原理如下:
- 哈希函數:將鍵轉換為數組索引。理想情況下,不同鍵應映射到不同索引,但沖突難以避免。
- 數組+鏈表:使用數組作為桶(Bucket),每個桶是一個鏈表,解決哈希沖突(鏈地址法)。
- 動態擴容:當元素數量超過容量與負載因子的乘積時,擴容并重新分配元素,保持操作高效性。
package mainimport "fmt"// Entry 鍵值對鏈表節點
type Entry struct {Key stringValue 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 = 2166136261prime = 16777619)hash := offsetfor _, 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) >= h.loadFactor {h.resize()}index := h.getIndex(key)entry := h.buckets[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, true}entry = entry.Next}return nil, false
}// Delete 刪除鍵
func (h *HashMap) Delete(key string) bool {index := h.getIndex(key)entry := h.buckets[index]var prev *Entryfor entry != nil {if entry.Key == key {if prev == nil {h.buckets[index] = entry.Next // 刪除頭節點} else {prev.Next = entry.Next // 中間或尾部節點}h.size--return true}prev = entryentry = entry.Next}return false
}// resize 擴容哈希表
func (h *HashMap) resize() {newCapacity := h.capacity * 2newBuckets := make([]*Entry, newCapacity)for i := 0; i < h.capacity; i++ {entry := h.buckets[i]for entry != nil {next := entry.NextnewIndex := h.hash(entry.Key) % newCapacity // 重新計算索引entry.Next = newBuckets[newIndex] // 插入新桶頭部newBuckets[newIndex] = entryentry = next}}h.buckets = newBucketsh.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") // 輸出此句}
}