哈希表 - 开放地址法 (Open Addressing)

所有元素存储在数组内,冲突时通过探测序列寻找下一个空槽位。无指针开销,缓存友好。


结构定义

typedef struct {
    char *key;
    int value;
    int occupied;      /* 0=空, 1=占用, 2=已删除(墓碑) */
} Slot;
 
typedef struct {
    Slot *slots;
    size_t capacity;
    size_t size;
} OHashMap;

探测策略

策略公式说明
线性探测h(k, i) = (h(k) + i) % m最简单,但易产生集群
二次探测h(k, i) = (h(k) + c1*i + c2*i²) % m减少一次集群
双重哈希h(k, i) = (h1(k) + i * h2(k)) % m最佳分散,需要两个哈希函数

函数签名

函数复杂度说明
void oh_init(OHashMap *h, size_t cap)O(cap)初始化
void oh_put(OHashMap *h, const char *key, int val)均摊 O(1)插入
int oh_get(OHashMap *h, const char *key, int *out)均摊 O(1)查找
int oh_remove(OHashMap *h, const char *key)均摊 O(1)标记为墓碑
void oh_rehash(OHashMap *h)O(n)扩容并丢弃墓碑
void oh_free(OHashMap *h)O(cap)释放

墓碑机制

删除元素时不设为空,而标记为”已删除”(墓碑)。查找时遇到墓碑继续探测,插入时可复用墓碑槽位。当墓碑过多时触发 rehash 清理。

#define SLOT_EMPTY   0
#define SLOT_OCCUPIED 1
#define SLOT_TOMBSTONE 2

链地址法 vs 开放地址法

特性链地址法开放地址法
内存开销每节点一个指针0
负载因子阈值可 > 1必须 < 1(通常 < 0.7)
缓存性能差(链表跳跃)好(连续内存)
删除简单需墓碑
扩容所有节点 rehash所有槽 rehash

跨语言参考