HiHuo
首页
博客
手册
工具
首页
博客
手册
工具
  • 学习 Redis

    • Redis 手写实现学习指南
    • 快速开始
    • Redis 架构总览与线程模型
    • RESP 协议与网络通信
    • 事件循环与 I/O 多路复用
    • 底层数据结构设计
    • 字符串与 SDS 实现
    • 哈希表与字典实现
    • 列表与跳表实现
    • 有序集合实现
    • 内存管理与对象系统
    • RDB 持久化机制
    • AOF 持久化机制
    • 混合持久化策略
    • 分布式锁实现
    • 缓存一致性策略
    • 主从复制机制
    • 哨兵模式实现
    • 内存优化与 GC 调优

哈希表与字典实现

学习目标

  • 深入理解哈希表的设计原理和冲突解决机制
  • 掌握渐进式 rehash 的完整实现和优化策略
  • 实现高效的哈希算法(MurmurHash/SipHash)
  • 理解负载因子和扩容策略的平衡
  • 对比分析字典与 Go map 的性能差异

哈希表基础理论

1. 哈希表原理

哈希表是一种通过哈希函数将键映射到数组索引的数据结构,实现 O(1) 的平均查找、插入和删除操作。

┌─────────────────────────────────────────────────────────────┐
│                    哈希表结构                                │
├─────────────────────────────────────────────────────────────┤
│  索引  │  键值对  │  键值对  │  键值对  │  键值对  │  键值对  │
│   0   │  key1   │  key2   │  key3   │  key4   │  key5   │
│       │  val1   │  val2   │  val3   │  val4   │  val5   │
├───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│   1   │  key6   │  key7   │  key8   │  key9   │  key10  │
│       │  val6   │  val7   │  val8   │  val9   │  val10  │
├───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│   2   │  key11  │  key12  │  key13  │  key14  │  key15  │
│       │  val11  │  val12  │  val13  │  val14  │  val15  │
└───────┴─────────┴─────────┴─────────┴─────────┴─────────┘

2. 哈希冲突解决

2.1 链地址法(Chaining)

每个槽位维护一个链表,冲突的键值对存储在链表中:

// 链地址法实现
type HashNode struct {
    key   string
    value interface{}
    next  *HashNode
}

type HashTable struct {
    buckets []*HashNode
    size    int
    count   int
}

2.2 开放地址法(Open Addressing)

当发生冲突时,在哈希表中寻找下一个可用的槽位:

  • 线性探测:h(k, i) = (h(k) + i) mod m
  • 二次探测:h(k, i) = (h(k) + i²) mod m
  • 双重哈希:h(k, i) = (h₁(k) + i·h₂(k)) mod m

️ Redis 字典设计

1. 字典结构

Redis 字典使用链地址法解决冲突,并支持渐进式 rehash:

// Redis 字典结构(简化版)
typedef struct dictEntry {
    void *key;              // 键
    union {
        void *val;          // 值
        uint64_t u64;       // 64位整数
        int64_t s64;        // 64位有符号整数
        double d;           // 双精度浮点数
    } v;
    struct dictEntry *next; // 指向下一个节点
} dictEntry;

typedef struct dictht {
    dictEntry **table;      // 哈希表数组
    unsigned long size;     // 哈希表大小
    unsigned long sizemask; // 哈希表大小掩码
    unsigned long used;     // 已使用节点数
} dictht;

typedef struct dict {
    dictType *type;         // 类型特定函数
    void *privdata;         // 私有数据
    dictht ht[2];           // 两个哈希表
    long rehashidx;         // rehash 索引
    int iterators;          // 迭代器数量
} dict;

2. 渐进式 Rehash

Redis 使用渐进式 rehash 避免一次性迁移大量数据造成的阻塞:

  1. 准备阶段:创建新的哈希表 ht[1]
  2. 渐进阶段:每次操作时迁移一部分数据
  3. 完成阶段:释放旧哈希表,完成 rehash

️ Go 语言字典实现

1. 基础结构定义

// dict/dict.go
package dict

import (
    "fmt"
    "hash/fnv"
    "math"
    "sync"
    "unsafe"
)

// 字典类型
type DictType struct {
    HashFunc  func(key interface{}) uint64
    EqualFunc func(key1, key2 interface{}) bool
    DupFunc   func(key interface{}) interface{}
    FreeFunc  func(key interface{})
}

// 字典条目
type DictEntry struct {
    key   interface{}
    value interface{}
    next  *DictEntry
}

// 哈希表
type DictHt struct {
    table    []*DictEntry
    size     uint64
    sizemask uint64
    used     uint64
}

// 字典
type Dict struct {
    dictType *DictType
    privdata interface{}
    ht       [2]*DictHt
    rehashidx int64
    iterators int64
    mu       sync.RWMutex
}

// 创建字典
func NewDict(dictType *DictType) *Dict {
    return &Dict{
        dictType:   dictType,
        ht:         [2]*DictHt{newDictHt(4), nil},
        rehashidx:  -1,
        iterators:  0,
    }
}

// 创建哈希表
func newDictHt(size uint64) *DictHt {
    return &DictHt{
        table:    make([]*DictEntry, size),
        size:     size,
        sizemask: size - 1,
        used:     0,
    }
}

2. 哈希函数实现

// dict/hash.go
package dict

import (
    "hash/fnv"
    "hash/maphash"
    "unsafe"
)

// 默认哈希函数(FNV-1a)
func defaultHashFunc(key interface{}) uint64 {
    switch k := key.(type) {
    case string:
        return hashString(k)
    case int:
        return hashInt(uint64(k))
    case int64:
        return hashInt(uint64(k))
    case uint64:
        return hashInt(k)
    case []byte:
        return hashBytes(k)
    default:
        // 使用反射获取字符串表示
        return hashString(fmt.Sprintf("%v", k))
    }
}

// 字符串哈希(FNV-1a)
func hashString(s string) uint64 {
    h := fnv.New64a()
    h.Write([]byte(s))
    return h.Sum64()
}

// 整数哈希
func hashInt(n uint64) uint64 {
    // 使用乘法哈希
    return n * 0x9e3779b97f4a7c15
}

// 字节数组哈希
func hashBytes(b []byte) uint64 {
    h := fnv.New64a()
    h.Write(b)
    return h.Sum64()
}

// SipHash 实现(Redis 使用)
func sipHash(key []byte, seed [16]byte) uint64 {
    // 简化的 SipHash 实现
    h := maphash.Hash{}
    h.SetSeed(maphash.MakeSeed())
    h.Write(key)
    return h.Sum64()
}

// MurmurHash 实现
func murmurHash(key []byte, seed uint32) uint32 {
    const (
        c1 = 0xcc9e2d51
        c2 = 0x1b873593
        r1 = 15
        r2 = 13
        m  = 5
        n  = 0xe6546b64
    )
    
    h := seed
    length := len(key)
    
    // 处理 4 字节块
    for i := 0; i < length-3; i += 4 {
        k := uint32(key[i]) | uint32(key[i+1])<<8 | uint32(key[i+2])<<16 | uint32(key[i+3])<<24
        k *= c1
        k = (k << r1) | (k >> (32 - r1))
        k *= c2
        h ^= k
        h = (h << r2) | (h >> (32 - r2))
        h = h*5 + n
    }
    
    // 处理剩余字节
    switch length & 3 {
    case 3:
        h ^= uint32(key[length-3]) << 16
        fallthrough
    case 2:
        h ^= uint32(key[length-2]) << 8
        fallthrough
    case 1:
        h ^= uint32(key[length-1])
        h *= c1
    }
    
    // 最终混合
    h ^= uint32(length)
    h ^= h >> 16
    h *= 0x85ebca6b
    h ^= h >> 13
    h *= 0xc2b2ae35
    h ^= h >> 16
    
    return h
}

3. 基础操作实现

// dict/operations.go
package dict

// 设置键值对
func (d *Dict) Set(key, value interface{}) error {
    d.mu.Lock()
    defer d.mu.Unlock()
    
    // 检查是否需要 rehash
    if d.isRehashing() {
        d.rehashStep()
    }
    
    // 计算哈希值
    hash := d.dictType.HashFunc(key)
    
    // 查找键是否已存在
    if entry := d.findEntry(key, hash); entry != nil {
        // 更新值
        entry.value = value
        return nil
    }
    
    // 添加新条目
    return d.addEntry(key, value, hash)
}

// 获取值
func (d *Dict) Get(key interface{}) (interface{}, bool) {
    d.mu.RLock()
    defer d.mu.RUnlock()
    
    hash := d.dictType.HashFunc(key)
    entry := d.findEntry(key, hash)
    
    if entry == nil {
        return nil, false
    }
    
    return entry.value, true
}

// 删除键
func (d *Dict) Delete(key interface{}) bool {
    d.mu.Lock()
    defer d.mu.Unlock()
    
    // 检查是否需要 rehash
    if d.isRehashing() {
        d.rehashStep()
    }
    
    hash := d.dictType.HashFunc(key)
    return d.deleteEntry(key, hash)
}

// 检查键是否存在
func (d *Dict) Exists(key interface{}) bool {
    d.mu.RLock()
    defer d.mu.RUnlock()
    
    hash := d.dictType.HashFunc(key)
    return d.findEntry(key, hash) != nil
}

// 获取字典大小
func (d *Dict) Size() uint64 {
    d.mu.RLock()
    defer d.mu.RUnlock()
    
    if d.isRehashing() {
        return d.ht[0].used + d.ht[1].used
    }
    
    return d.ht[0].used
}

// 清空字典
func (d *Dict) Clear() {
    d.mu.Lock()
    defer d.mu.Unlock()
    
    // 清空两个哈希表
    for i := 0; i < 2; i++ {
        if d.ht[i] != nil {
            d.clearHt(d.ht[i])
        }
    }
    
    d.rehashidx = -1
}

// 清空哈希表
func (d *Dict) clearHt(ht *DictHt) {
    for i := uint64(0); i < ht.size; i++ {
        entry := ht.table[i]
        for entry != nil {
            next := entry.next
            if d.dictType.FreeFunc != nil {
                d.dictType.FreeFunc(entry.key)
                d.dictType.FreeFunc(entry.value)
            }
            entry = next
        }
        ht.table[i] = nil
    }
    ht.used = 0
}

4. 查找和添加操作

// dict/find_add.go
package dict

// 查找条目
func (d *Dict) findEntry(key interface{}, hash uint64) *DictEntry {
    // 检查两个哈希表
    for i := 0; i < 2; i++ {
        ht := d.ht[i]
        if ht == nil {
            continue
        }
        
        // 计算索引
        index := hash & ht.sizemask
        
        // 遍历链表
        entry := ht.table[index]
        for entry != nil {
            if d.dictType.EqualFunc(entry.key, key) {
                return entry
            }
            entry = entry.next
        }
        
        // 如果不在 rehash 中,只检查第一个表
        if !d.isRehashing() {
            break
        }
    }
    
    return nil
}

// 添加条目
func (d *Dict) addEntry(key, value interface{}, hash uint64) error {
    // 选择哈希表
    ht := d.ht[0]
    if d.isRehashing() {
        ht = d.ht[1]
    }
    
    // 检查是否需要扩容
    if !d.isRehashing() && d.needRehash() {
        return d.expand()
    }
    
    // 计算索引
    index := hash & ht.sizemask
    
    // 创建新条目
    entry := &DictEntry{
        key:   key,
        value: value,
        next:  ht.table[index],
    }
    
    // 插入到链表头部
    ht.table[index] = entry
    ht.used++
    
    return nil
}

// 删除条目
func (d *Dict) deleteEntry(key interface{}, hash uint64) bool {
    // 检查两个哈希表
    for i := 0; i < 2; i++ {
        ht := d.ht[i]
        if ht == nil {
            continue
        }
        
        // 计算索引
        index := hash & ht.sizemask
        
        // 遍历链表
        entry := ht.table[index]
        var prev *DictEntry
        
        for entry != nil {
            if d.dictType.EqualFunc(entry.key, key) {
                // 删除条目
                if prev == nil {
                    ht.table[index] = entry.next
                } else {
                    prev.next = entry.next
                }
                
                // 释放内存
                if d.dictType.FreeFunc != nil {
                    d.dictType.FreeFunc(entry.key)
                    d.dictType.FreeFunc(entry.value)
                }
                
                ht.used--
                return true
            }
            
            prev = entry
            entry = entry.next
        }
        
        // 如果不在 rehash 中,只检查第一个表
        if !d.isRehashing() {
            break
        }
    }
    
    return false
}

5. 渐进式 Rehash 实现

// dict/rehash.go
package dict

// 检查是否需要 rehash
func (d *Dict) needRehash() bool {
    ht := d.ht[0]
    
    // 如果哈希表为空,需要初始化
    if ht.size == 0 {
        return true
    }
    
    // 负载因子超过 1 时扩容
    if ht.used >= ht.size {
        return true
    }
    
    // 负载因子小于 0.1 时缩容
    if ht.used < ht.size/10 && ht.size > 4 {
        return true
    }
    
    return false
}

// 开始 rehash
func (d *Dict) expand() error {
    ht := d.ht[0]
    newSize := ht.size
    
    // 计算新大小
    if ht.used >= ht.size {
        newSize = ht.size * 2
    } else if ht.used < ht.size/10 && ht.size > 4 {
        newSize = ht.size / 2
    }
    
    // 创建新哈希表
    d.ht[1] = newDictHt(newSize)
    d.rehashidx = 0
    
    return nil
}

// 检查是否在 rehash
func (d *Dict) isRehashing() bool {
    return d.rehashidx != -1
}

// 执行一步 rehash
func (d *Dict) rehashStep() {
    if !d.isRehashing() {
        return
    }
    
    // 每次迁移一个桶
    ht0 := d.ht[0]
    ht1 := d.ht[1]
    
    for ht0.used > 0 && d.rehashidx < int64(ht0.size) {
        // 跳过空桶
        if ht0.table[d.rehashidx] == nil {
            d.rehashidx++
            continue
        }
        
        // 迁移整个链表
        entry := ht0.table[d.rehashidx]
        ht0.table[d.rehashidx] = nil
        
        for entry != nil {
            next := entry.next
            
            // 计算新索引
            hash := d.dictType.HashFunc(entry.key)
            newIndex := hash & ht1.sizemask
            
            // 插入到新表
            entry.next = ht1.table[newIndex]
            ht1.table[newIndex] = entry
            
            ht0.used--
            ht1.used++
            
            entry = next
        }
        
        d.rehashidx++
    }
    
    // 检查是否完成 rehash
    if ht0.used == 0 {
        d.ht[0] = d.ht[1]
        d.ht[1] = nil
        d.rehashidx = -1
    }
}

// 强制完成 rehash
func (d *Dict) rehashAll() {
    for d.isRehashing() {
        d.rehashStep()
    }
}

6. 迭代器实现

// dict/iterator.go
package dict

// 字典迭代器
type DictIterator struct {
    dict    *Dict
    table   int
    index   int64
    entry   *DictEntry
    next    *DictEntry
    safe    bool
}

// 创建迭代器
func (d *Dict) NewIterator(safe bool) *DictIterator {
    d.mu.Lock()
    defer d.mu.Unlock()
    
    if safe {
        d.iterators++
    }
    
    return &DictIterator{
        dict:  d,
        table: 0,
        index: -1,
        safe:  safe,
    }
}

// 获取下一个条目
func (iter *DictIterator) Next() *DictEntry {
    if iter.entry == nil {
        return nil
    }
    
    entry := iter.entry
    iter.entry = iter.next
    
    return entry
}

// 重置迭代器
func (iter *DictIterator) Reset() {
    iter.table = 0
    iter.index = -1
    iter.entry = nil
    iter.next = nil
}

// 关闭迭代器
func (iter *DictIterator) Close() {
    if iter.safe {
        iter.dict.mu.Lock()
        iter.dict.iterators--
        iter.dict.mu.Unlock()
    }
}

// 查找下一个条目
func (iter *DictIterator) findNext() {
    for iter.table < 2 {
        ht := iter.dict.ht[iter.table]
        if ht == nil {
            iter.table++
            iter.index = -1
            continue
        }
        
        for iter.index < int64(ht.size) {
            if ht.table[iter.index] != nil {
                iter.entry = ht.table[iter.index]
                iter.next = iter.entry.next
                return
            }
            iter.index++
        }
        
        iter.table++
        iter.index = -1
    }
    
    iter.entry = nil
    iter.next = nil
}

测试验证

1. 单元测试

// dict/dict_test.go
package dict

import (
    "testing"
)

func TestDictBasic(t *testing.T) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 测试设置和获取
    d.Set("key1", "value1")
    d.Set("key2", "value2")
    
    val, exists := d.Get("key1")
    if !exists || val != "value1" {
        t.Errorf("Expected 'value1', got %v", val)
    }
    
    val, exists = d.Get("key2")
    if !exists || val != "value2" {
        t.Errorf("Expected 'value2', got %v", val)
    }
    
    // 测试删除
    if !d.Delete("key1") {
        t.Error("Failed to delete key1")
    }
    
    _, exists = d.Get("key1")
    if exists {
        t.Error("Key1 should not exist after deletion")
    }
    
    // 测试大小
    if d.Size() != 1 {
        t.Errorf("Expected size 1, got %d", d.Size())
    }
}

func TestDictRehash(t *testing.T) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 添加大量数据触发 rehash
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
    
    // 验证数据完整性
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key%d", i)
        expected := fmt.Sprintf("value%d", i)
        
        val, exists := d.Get(key)
        if !exists || val != expected {
            t.Errorf("Expected '%s', got %v", expected, val)
        }
    }
}

func TestDictIterator(t *testing.T) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 添加测试数据
    testData := map[string]string{
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    }
    
    for k, v := range testData {
        d.Set(k, v)
    }
    
    // 测试迭代器
    iter := d.NewIterator(true)
    defer iter.Close()
    
    count := 0
    for entry := iter.Next(); entry != nil; entry = iter.Next() {
        key := entry.key.(string)
        value := entry.value.(string)
        
        if expected, exists := testData[key]; !exists || value != expected {
            t.Errorf("Expected '%s' for key '%s', got '%s'", expected, key, value)
        }
        count++
    }
    
    if count != len(testData) {
        t.Errorf("Expected %d entries, got %d", len(testData), count)
    }
}

2. 性能基准测试

// dict/benchmark_test.go
package dict

import (
    "testing"
)

func BenchmarkDictSet(b *testing.B) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
}

func BenchmarkDictGet(b *testing.B) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 预填充数据
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i%1000)
        d.Get(key)
    }
}

func BenchmarkDictDelete(b *testing.B) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 预填充数据
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i)
        d.Delete(key)
    }
}

func BenchmarkGoMapSet(b *testing.B) {
    m := make(map[string]string)
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        m[key] = value
    }
}

func BenchmarkGoMapGet(b *testing.B) {
    m := make(map[string]string)
    
    // 预填充数据
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        m[key] = value
    }
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        key := fmt.Sprintf("key%d", i%1000)
        _ = m[key]
    }
}

3. 内存使用测试

// dict/memory_test.go
package dict

import (
    "runtime"
    "testing"
)

func TestDictMemoryUsage(t *testing.T) {
    var m1, m2 runtime.MemStats
    runtime.ReadMemStats(&m1)
    
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 添加大量数据
    for i := 0; i < 10000; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
    
    runtime.ReadMemStats(&m2)
    
    heapGrowth := m2.HeapAlloc - m1.HeapAlloc
    t.Logf("Memory usage: %d bytes", heapGrowth)
    
    if heapGrowth > 50*1024*1024 { // 50MB
        t.Errorf("Memory usage too high: %d bytes", heapGrowth)
    }
}

func TestDictRehashMemory(t *testing.T) {
    dictType := &DictType{
        HashFunc:  defaultHashFunc,
        EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
    }
    
    d := NewDict(dictType)
    
    // 添加数据触发 rehash
    for i := 0; i < 1000; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        d.Set(key, value)
    }
    
    // 验证 rehash 状态
    if d.isRehashing() {
        t.Log("Dictionary is rehashing")
    }
    
    // 强制完成 rehash
    d.rehashAll()
    
    if d.isRehashing() {
        t.Error("Dictionary should not be rehashing after rehashAll")
    }
}

性能对比分析

1. 操作复杂度对比

操作平均情况最坏情况说明
查找O(1)O(n)哈希冲突时退化为链表
插入O(1)O(n)需要检查重复键
删除O(1)O(n)需要遍历链表
迭代O(n)O(n)需要遍历所有条目

2. 内存使用对比

特性自定义字典Go Map说明
内存开销较高较低需要存储指针和元数据
内存对齐手动自动Go 编译器优化
垃圾回收手动自动需要手动管理内存
内存碎片可能较少Go 内存分配器优化

3. 性能测试结果

// 基准测试结果示例
func BenchmarkComparison(b *testing.B) {
    // 自定义字典性能
    b.Run("CustomDict", func(b *testing.B) {
        dictType := &DictType{
            HashFunc:  defaultHashFunc,
            EqualFunc: func(k1, k2 interface{}) bool { return k1 == k2 },
        }
        d := NewDict(dictType)
        
        for i := 0; i < b.N; i++ {
            key := fmt.Sprintf("key%d", i)
            value := fmt.Sprintf("value%d", i)
            d.Set(key, value)
        }
    })
    
    // Go Map 性能
    b.Run("GoMap", func(b *testing.B) {
        m := make(map[string]string)
        
        for i := 0; i < b.N; i++ {
            key := fmt.Sprintf("key%d", i)
            value := fmt.Sprintf("value%d", i)
            m[key] = value
        }
    })
}

面试要点

1. 哈希冲突的解决方法

答案要点:

  • 链地址法:每个槽位维护链表,简单但可能退化为 O(n)
  • 开放地址法:在哈希表中寻找下一个可用槽位
  • 双重哈希:使用两个哈希函数减少冲突
  • 布谷鸟哈希:使用两个哈希表,冲突时踢出旧元素

2. 渐进式 Rehash 的优势

答案要点:

  • 避免阻塞:不会一次性迁移大量数据
  • 平滑过渡:在操作过程中逐步完成迁移
  • 内存控制:避免内存使用峰值过高
  • 响应性:保持操作的响应时间稳定

3. 负载因子的选择

答案要点:

  • 扩容阈值:通常选择 0.75,平衡空间和时间
  • 缩容阈值:通常选择 0.1,避免频繁扩容
  • 动态调整:根据使用模式调整阈值
  • 性能考虑:过高导致冲突,过低浪费空间

4. 哈希函数的选择

答案要点:

  • 均匀分布:减少冲突,提高性能
  • 计算效率:快速计算,减少开销
  • 抗攻击性:防止哈希碰撞攻击
  • 平台兼容:在不同平台上表现一致

总结

通过本章学习,我们深入理解了:

  1. 哈希表的设计原理和冲突解决机制
  2. 渐进式 rehash的完整实现和优化策略
  3. 高效哈希算法的实现和选择
  4. 负载因子和扩容策略的平衡
  5. 与 Go map 的性能对比分析

字典为 Redis 提供了高效的键值存储基础。在下一章中,我们将学习列表与跳表实现,了解 Redis 如何实现有序列表和范围查询。

Prev
字符串与 SDS 实现
Next
列表与跳表实现