C++ 哈希表原理与模拟实现
哈希表基础
哈希表(Hash Table)是一种通过键(Key)直接访问值(Value)的数据结构。其核心思想是利用哈希函数将任意大小的键映射为固定大小的整数(哈希值),再将其作为数组索引存储数据。理想情况下,查找、插入和删除的时间复杂度接近 O(1)。
负载因子与扩容
哈希表的效率高度依赖负载因子(Load Factor),即已存元素数量与数组总大小的比值。
- 负载因子低:空位多,冲突少,速度快。
- 负载因子高:空位少,冲突增加,性能下降。
通常设定阈值(如 0.75)。当超过阈值时,需进行扩容(Rehashing):创建更大的新数组(通常为原大小两倍),将所有旧元素重新计算哈希并插入新表,以维持常数级操作效率。
哈希冲突处理
由于输入空间远大于输出空间,不同键可能映射到同一位置,即哈希冲突。主流解决策略有两种:
- 开放寻址法(Open Addressing):冲突时在数组内寻找下一个空闲槽位。典型代表是线性探测法,所有数据存储在数组中,缓存友好,但删除较复杂。
- 链地址法(Separate Chaining):每个数组位置挂一个链表(或树)。冲突元素存入链表,删除方便,但需要额外指针空间,内存不连续。
线性探测法模拟实现
线性探测属于开放寻址法。当发生冲突时,依次向后检查直到找到空位。为了支持删除操作,我们需要标记节点状态:EXIST(存在)、EMPTY(空)、DELETE(逻辑删除)。
数据结构定义
#pragma once
#include <vector>
#include <string>
using namespace std;
enum STATE { EXIST, EMPTY, DELETE };
template<class K, class V>
struct HashData {
pair<K, V> _kv;
STATE _state = EMPTY;
};
哈希函数设计
针对不同类型键,哈希函数需适配。对于整数可直接转换,字符串则需专用算法(如 BKDR)以保证分布均匀。
template<class K>
struct DefaultHashFunc {
{
()key;
}
};
<>
<string> {
{
hash = ;
( ch : str) {
hash *= ;
hash += ch;
}
hash;
}
};


