摘要 :掌握高频数据结构!今日深入解析哈希表的核心原理与设计实现,结合冲突解决策略与大厂高频真题,彻底掌握O(1)时间复杂度的数据访问技术。
一、哈希表核心思想
哈希表(Hash Table) 是一种基于键值对的高效数据结构,通过哈希函数将键映射到存储位置,核心特性:
-
平均时间复杂度:插入、删除、查找均为O(1)
-
冲突处理:开放寻址法、链地址法等策略
-
负载因子:哈希表性能的关键指标(元素数/桶数)
应用场景 :
-
快速数据检索
-
去重操作
-
缓存系统设计(如LRU Cache)
二、哈希表实现原理
1. 哈希函数设计
理想哈希函数特性 :
-
确定性:相同键的哈希值始终相同
-
均匀性:键值均匀分布到各个桶
-
高效性:计算速度快
常见哈希函数 :
-
除法哈希:hash(key) = key % capacity
-
乘法哈希:利用黄金分割点
-
多项式哈希:用于字符串处理
// 字符串哈希示例(多项式滚动哈希)
size_t stringHash(const string& s, size_t mod = 1e9+7) {
size_t hash = 0;
const size_t base = 31; // 常用质数基数
for (char c : s) {
hash = (hash * base + c) % mod;
}
return hash;
}
2. 冲突解决策略
动态示意图 :
链地址法示意图
策略1:链地址法(Separate Chaining)
// 哈希表节点定义
template <typename K, typename V>
struct HashNode {
K key;
V value;
HashNode* next;
HashNode(K k, V v) : key(k), value(v), next(nullptr) {}
};
// 哈希表类框架
template <typename K, typename V>
class HashMap {
private:
vector<HashNode<K,V>*> buckets;
size_t capacity;
size_t size;
size_t hashFunction(K key) {
return hash<K>{}(key) % capacity;
}
public:
HashMap(size_t cap = 16) : capacity(cap), size(0) {
buckets.resize(cap, nullptr);
}
// 插入、查找、删除操作实现...
};
策略2:开放寻址法(Open Addressing)
// 线性探测插入实现
template <typename K, typename V>
void HashMap<K,V>::put(K key, V value) {
size_t index = hashFunction(key);
while (buckets[index] != nullptr) {
if (buckets[index]->key == key) { // 已存在则更新
buckets[index]->value = value;
return;
}
index = (index + 1) % capacity; // 线性探测
}
buckets[index] = new HashNode<K,V>(key, value);
size++;
}
三、哈希表操作实现(C++)
1. 插入操作(链地址法)
template <typename K, typename V>
void HashMap<K,V>::put(K key, V value) {
size_t index = hashFunction(key);
HashNode<K,V>* node = buckets[index];
while (node) { // 检查键是否已存在
if (node->key == key) {
node->value = value;
return;
}
node = node->next;
}
// 头插法添加新节点
HashNode<K,V>* newNode = new HashNode<K,V>(key, value);
newNode->next = buckets[index];
buckets[index] = newNode;
size++;
}
2. 查找操作、
template <typename K, typename V>
V HashMap<K,V>::get(K key) {
size_t index = hashFunction(key);
HashNode<K,V>* node = buckets[index];
while (node) {
if (node->key == key) {
return node->value;
}
node = node->next;
}
throw out_of_range("Key not found");
}
3. 删除操作
template <typename K, typename V>
void HashMap<K,V>::remove(K key) {
size_t index = hashFunction(key);
HashNode<K,V>* node = buckets[index];
HashNode<K,V>* prev = nullptr;
while (node) {
if (node->key == key) {
if (prev) prev->next = node->next;
else buckets[index] = node->next;
delete node;
size--;
return;
}
prev = node;
node = node->next;
}
}
四、复杂度与优化
操作 | 平均情况 | 最坏情况 |
---|---|---|
插入 | O(1) | O(n) |
删除 | O(1) | O(n) |
查找 | O(1) | O(n) |
优化策略 :
-
负载因子监控:当元素数/桶数超过阈值(如0.75),触发扩容
-
动态扩容:容量扩展为原来的2倍,并重新哈希所有元素
-
良好的哈希函数选择:减少冲突,提升性能