C++ STL 进阶:unordered_set 与 unordered_map 模拟实现
标准库背景
在 SGI STL 30 版本(C++11 之前)中,unordered_set和 unordered_map尚未出现。当时对应的非标准容器是 hash_set和 hash_map,其核心实现位于 stl_hashtable.h、stl_hash_set及 stl_hash_map文件中。
从源码结构可以看出,hash_set和 hash_map复用了同一个 hashtable类来实现关键结构,以此适配不同的存储与查找需求。对于 hash_set,传递给 hashtable的是单纯的 key;对于 hash_map,则是 pair<const key, value>这种键值对形式。C++11 标准在此基础上进行了规范化。
代码实现架构
哈希表基础 (HashTable.h)
这是整个容器的底层支撑,采用链地址法处理冲突。主要包含节点定义、迭代器设计、扩容策略及核心操作。
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*------------------ 任务:定义哈希函数的'通用类模板' ------------------*/
template<class K>
struct HashFunc {
// 重载 () 运算符,将 K 类型转化为 size_t 类型,用于计算哈希值
size_t operator()(const K& key) {
return (size_t)key; // 默认为直接转换,适用于 int、long 等整数类型
}
};
/*------------------ 任务:定义哈希函数的'模板特化' ------------------*/
template<>
struct <string> {
{
hash = ;
( it : s) {
hash += it;
hash *= ;
}
hash;
}
};
_stl_next_prime( n) {
_stl_num_primes = ;
_stl_prime_list[_stl_num_primes] = {
, , , , , , , , , ,
, , , , , , ,
, , , , , ,
, , , ,
};
* first = _stl_prime_list;
* last = _stl_prime_list + _stl_num_primes;
* pos = (first, last, n);
pos == last ? *(last - ) : *pos;
}
hash_bucket {
< >
{
T _data;
HashNode<T>* _next;
( T& data) : _data(data), _next() {}
};
< , , , >
;
< , , , , , >
{
HashNode<T>* _node;
HashTable<K, T, KeyOfT, Hash>* _ht;
HashNode<T> Node;
HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;
HashTable<K, T, KeyOfT, Hash> HT;
(Node* node, HT* ht) : _node(node), _ht(ht) {}
Ref *() { _node->_data; }
Ptr ->() { &_node->_data; }
!=( Self& other) { _node != other._node; }
==( Self& other) { _node == other._node; }
Self& ++() {
(_node->_next) {
_node = _node->_next;
} {
KeyOfT kot;
Hash hashFunc;
hash_i = ((_node->_data)) % _ht->_tables.();
++hash_i;
(hash_i < _ht->_tables.()) {
_node = _ht->_tables[hash_i];
(_node) ;
++hash_i;
}
(hash_i == _ht->_tables.()) {
_node = ;
}
}
*;
}
};
< , , , >
{
:
vector<HashNode<T>*> _tables;
_n;
HashNode<T> Node;
<K, T, T&, T*, KeyOfT, Hash>;
<K, T, T&, T*, KeyOfT, Hash>;
:
HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;
HTIterator<K, T, T&, T*, KeyOfT, Hash> ConstIterator;
{
(_n == ) ();
( i = ; i < _tables.(); i++) {
Node* current = _tables[i];
(current) (current, );
}
();
}
{ (, ); }
{
(_n == ) ();
( i = ; i < _tables.(); i++) {
Node* current = _tables[i];
(current) (current, );
}
();
}
{ (, ); }
() : _tables(_stl_next_prime()), _n() {}
~() {
( i = ; i < _tables.(); ++i) {
Node* current = _tables[i];
(current) {
Node* next = current->_next;
current;
current = next;
}
_tables[i] = ;
}
}
{
KeyOfT kot;
Hash hashFunc;
hash_i = (key) % _tables.();
Node* current = _tables[hash_i];
(current) {
((current->_data) == key) (current, );
current = current->_next;
}
();
}
{
KeyOfT kot;
Hash hashFunc;
hash_i = (key) % _tables.();
Node* curr = _tables[hash_i];
Node* prev = ;
(curr) {
((curr->_data) == key) {
(prev == ) _tables[hash_i] = curr->_next;
prev->_next = curr->_next;
curr;
--_n;
;
}
prev = curr;
curr = curr->_next;
}
;
}
{
KeyOfT kot;
Iterator it = ((data));
(it != ()) { it, };
(_n == _tables.()) {
;
( i = ; i < _tables.(); i++) {
Node* current = _tables[i];
(current) {
Node* next = current->_next;
hash_i = ((current->_data)) % newVector.();
current->_next = newVector[hash_i];
newVector[hash_i] = current;
current = next;
}
_tables[i] = ;
}
_tables.(newVector);
}
Node* newNode = (data);
Hash hashFunc;
hash_i = ((data)) % _tables.();
newNode->_next = _tables[hash_i];
_tables[hash_i] = newNode;
++_n;
{ (newNode, ), };
}
};
}


