Unordered 系列容器概述
在 C++98 中,STL 提供了底层为红黑树的关联式容器(map/set),查询效率为 O(logN)。为了追求极致的查找速度,C++11 引入了 unordered 系列容器,其底层采用哈希表结构,理论上查询效率可达到 O(1)。
本文将模拟实现代码(HashBucket, UnorderedMap, UnorderedSet),深入剖析其底层原理与实现细节。
1. 哈希基础与冲突解决
1.1 哈希概念
哈希(Hash)通过一个哈希函数(HashFunc),将元素的关键码(Key)映射到存储位置,建立一一映射关系,从而实现不经过比较直接查找元素。
公式:hash(key) = key % capacity
1.2 哈希冲突
当不同的关键字通过哈希函数计算出相同的哈希地址时,就会发生哈希冲突(Hash Collision)。解决冲突主要有两种方式:
A. 闭散列(开放定址法)
当发生冲突时,如果哈希表未满,将 key 存放到冲突位置的'下一个'空位置。
线性探测:挨个往后找。容易产生'数据堆积'。
二次探测:通过跳转查找,缓解堆积。
B. 开散列(链地址法/哈希桶)
这是 STL unordered_map 通常采用的方法,也是我们代码中实现的方法。
原理:将具有相同哈希地址的元素归于同一子集合(桶),每个桶通过单链表链接。哈希表中存储的是链表的头指针。
2. 模拟实现:底层哈希桶 (HashBucket)
我们在 HashBucket.h 中实现了开散列的哈希表。
2.1 节点设计
使用模板结构体 HashNode,存储数据和下一个节点的指针。
template <class T>
struct HashNode {
T _data;
HashNode* _next;
// ... 构造函数
};
2.2 哈希函数与字符串特化
为了支持 string 作为 Key,我们需要对哈希函数进行特化。代码中使用了类似 BKDRHash 的思路(乘数为 31)将字符串转化为整型。
template <>
struct HashFunc<string> {
const int operator()(const string& str) {
int hashi = ;
( i = ; i < str.(); i++) {
hashi += str[i];
hashi *= ;
}
hashi;
}
};


