C++ STL 进阶:unordered_set 与 unordered_map 模拟实现
标准库实现原理
在 SGI STL30 版本(C++11 之前)中,unordered_set和 unordered_map尚未引入。当时的哈希表功能由非标准容器 hash_set 和 hash_map 提供,其核心依赖于 stl_hashtable.h。
从源码结构来看,hash_set和 hash_map复用了同一个 hashtable 模板类来实现底层存储。对于 hash_set,传递给 hashtable 的是单纯的键类型;而对于 hash_map,则传递 pair<const Key, T> 形式的键值对。这种设计使得底层哈希表能够灵活适配不同的存储需求。
代码实现架构
容器结构设计
无序容器的底层基于链地址法实现的哈希表。主要包含以下组件:
- 哈希节点:存储数据及指向下一个节点的指针。
- 桶数组:vector 容器存储各桶的头节点指针。
- 迭代器:支持单向遍历,需处理跨桶跳转逻辑。
核心模块
1. 哈希函数与质数扩容
为了减少冲突,哈希表容量通常选择质数。我们实现了获取大于等于指定数的最小质数函数 _stl_next_prime,并在扩容时查找新容量。
针对字符串类型的哈希计算,采用 BKDR 算法(乘以质数 131),相比直接转换能更好地分散哈希值。
// HashFunc 模板特化示例
template<>
struct HashFunc<string> {
size_t operator()(const string& s) {
size_t hash = 0;
for (auto it : s) {
hash += it;
hash *= 131; // BKDR 算法核心
}
return hash;
}
};
2. 哈希表节点与迭代器
哈希表节点结构简单,包含数据和 next 指针。迭代器设计较为关键,除了当前节点指针外,还需持有哈希表对象的指针,以便在链表遍历结束后寻找下一个非空桶。
template<class K, class T, , , , >
{
HashNode<T>* _node;
HashTable<K, T, KeyOfT, Hash>* _ht;
Self& ++() {
(_node->_next) {
_node = _node->_next;
} {
hash_i = ((_node->_data)) % _ht->_tables.();
++hash_i;
(hash_i < _ht->_tables.()) {
(_ht->_tables[hash_i]) ;
++hash_i;
}
(hash_i == _ht->_tables.()) _node = ;
}
*;
}
};


