unordered_set是C++标准库提供的一种无序关联容器,其底层实现基于哈希表。与传统的set相比,它提供了更高效的查找性能,平均时间复杂度为O(1)。
类模板声明解析:
template <
class Key, // 元素类型
class Hash = hash<Key>, // 哈希函数对象
class Pred = equal_to<Key>, // 键值相等比较函数
class Alloc = allocator<Key> // 内存分配器
> class unordered_set;
底层数据结构:
元素排序:
性能特点:
迭代器特性:
两种容器在不同操作上的时间差异:
#include
#include
#include
#include
#include
using namespace std;
void test_performance() {
const size_t N = 100000; // 测试数据量
// 生成测试数据
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t i = 0; i < N; ++i) {
v.push_back(rand()); // 随机数据,可能有重复
}
// 测试set
set<int> s;
clock_t begin1 = clock();
for (auto e : v) s.insert(e);
clock_t end1 = clock();
cout << "set插入耗时: " << (end1 - begin1) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
// 测试unordered_set
unordered_set<int> us;
us.reserve(N); // 预分配空间提升性能
clock_t begin2 = clock();
for (auto e : v) us.insert(e);
clock_t end2 = clock();
cout << "unordered_set插入耗时: " << (end2 - begin2) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
// 测试查找性能
int found1 = 0, found2 = 0;
clock_t begin3 = clock();
for (auto e : v) if (s.find(e) != s.end()) ++found1;
clock_t end3 = clock();
cout << "set查找耗时: " << (end3 - begin3) * 1000 / CLOCKS_PER_SEC << " ms (找到" << found1 << "个)" << endl;
clock_t begin4 = clock();
for (auto e : v) if (us.find(e) != us.end()) ++found2;
clock_t end4 = clock();
cout << "unordered_set查找耗时: " << (end4 - begin4) * 1000 / CLOCKS_PER_SEC << " ms (找到" << found2 << "个)" << endl;
// 测试删除性能
clock_t begin5 = clock();
for (auto e : v) s.erase(e);
clock_t end5 = clock();
cout << "set删除耗时: " << (end5 - begin5) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
clock_t begin6 = clock();
for (auto e : v) us.erase(e);
clock_t end6 = clock();
cout << "unordered_set删除耗时: " << (end6 - begin6) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
}
int main() {
test_performance();
return 0;
}
实验结果分析:
unordered_map与map的差异类似于unordered_set与set的差异:
键值要求:
迭代器特性:
性能差异:
标准库还提供了允许键值重复的版本:
这些变体与普通版本的差异主要体现在:
unordered_xxx系列容器提供了一些与哈希策略相关的接口,包括:
这些接口在日常使用中较少涉及,但在需要精细控制哈希表性能时非常有用。
选择容器时的考虑因素:
性能优化建议:
使用场景推荐:
#pragma once
#include
// 获取大于等于n的下一个质数
inline unsigned long __stl_next_prime(unsigned long n)
{
// 假设long至少32位
static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] = {
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473, 4294967291
};
const unsigned long* first = __stl_prime_list;
const unsigned long* last = __stl_prime_list + __stl_num_primes;
const unsigned long* pos = lower_bound(first, last, n);
return pos == last ? *(last - 1) : *pos;
}
// 哈希函数模板
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
// 字符串特化的哈希函数
template<>
struct HashFunc<string>
{
size_t operator()(const string& s)
{
// BKDR哈希算法
size_t hash = 0;
for (auto ch : s)
{
hash += ch;
hash *= 131;
}
return hash;
}
};
namespace hash_bucket
{
// 哈希节点模板
template<class T>
struct HashNode
{
T _data; // 存储的数据
HashNode<T>* _next; // 指向下一个节点的指针
HashNode(const T& data)
:_data(data)
, _next(nullptr)
{}
};
// 前置声明
template<class K, class T, class KeyOfT, class Hash>
class HashTable;
// 哈希表迭代器
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HTIterator
{
typedef HTIterator<K,T, Ref, Ptr, KeyOfT, Hash> Self;
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash> HT;
Node* _node; // 当前节点指针
const HT* _ht; // 所属哈希表指针
HTIterator(Node* node, const HT* ht)
:_node(node)
,_ht(ht)
{}
// 解引用操作符
Ref operator*()
{
return _node->_data;
}
// 箭头操作符
Ptr operator->()
{
return &_node->_data;
}
// 不等于操作符
bool operator!=(const Self& s)
{
return _node != s._node;
}
// 前置++操作符
Self& operator++()
{
if (_node->_next)
{
// 当前桶还有数据,移动到下一个节点
_node = _node->_next;
}
else
{
// 当前桶走完了,找下一个有数据的桶
KeyOfT kot;
Hash hash;
size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();
++hashi;
while (hashi < _ht->_tables.size())
{
_node = _ht->_tables[hashi];
if (_node)
break;
else
++hashi;
}
if (hashi == _ht->_tables.size()) // 走到结尾了
{
_node = nullptr; // end()是空标识
}
}
return *this;
}
};
// 哈希表模板
template<class K, class T, class KeyOfT, class Hash>
class HashTable
{
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
friend struct HTIterator;
typedef HashNode<T> Node;
public:
// 迭代器类型定义
typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;
typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> Const_Iterator;
// 获取起始迭代器
Iterator Begin()
{
if(_n == 0)
{
return End();
}
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
if (cur)
return Iterator(cur, this);
}
return End();
}
// 获取结束迭代器
Iterator End()
{
return Iterator(nullptr, this);
}
// 获取常量起始迭代器
Const_Iterator Begin() const
{
if (_n == 0)
{
return End();
}
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
if (cur)
return Const_Iterator(cur, this);
}
return End();
}
// 获取常量结束迭代器
Const_Iterator End() const
{
return Const_Iterator(nullptr, this);
}
// 构造函数
HashTable()
:_tables(__stl_next_prime(0))
, _n(0)
{}
// 析构函数
~HashTable()
{
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tables[i] = nullptr;
}
}
// 插入元素
pair<Iterator,bool> Insert(const T& data)
{
Hash hash;
KeyOfT kot;
Iterator it = Find(kot(data));
if (it != End())
{
return { it,false }; // 元素已存在
}
// 负载因子 == 1时扩容
if (_n == _tables.size())
{
vector<Node*> newTable(__stl_next_prime(_tables.size()+1));
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
// 头插到新表
size_t hashi = hash(kot(cur->_data)) % newTable.size();
cur->_next = newTable[hashi];
newTable[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
_tables.swap(newTable);
}
size_t hashi = hash(kot(data)) % _tables.size();
// 头插
Node* newnode = new Node(data);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n;
return { Iterator(newnode,this),true };
}
// 查找元素
Iterator Find(const K& key)
{
KeyOfT kot;
Hash hash;
size_t hashi = hash(key) % _tables.size();
Node* cur = _tables[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
return Iterator(cur,this);
}
cur = cur->_next;
}
return End();
}
// 删除元素
bool Erase(const K& key)
{
KeyOfT kot;
Hash hash;
size_t hashi = hash(key) % _tables.size();
Node* prev = nullptr;
Node* cur = _tables[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
// 删除头节点
if (prev == nullptr)
{
_tables[hashi] = cur->_next;
}
// 删除中间节点
else
{
prev->_next = cur->_next;
}
delete cur;
--_n;
return true;
}
else
{
prev = cur;
cur = cur->_next;
}
}
return false;
}
private:
vector<Node*> _tables; // 指针数组,存储哈希桶
size_t _n = 0; // 表中存储数据个数
};
}
#pragma once
#include"HashTable.h"
namespace sty
{
// unordered_map 模板类
template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
// 从pair中提取key的仿函数
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
// 迭代器类型定义
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Const_Iterator const_iterator;
// 获取起始迭代器
iterator begin()
{
return _ht.Begin();
}
// 获取结束迭代器
iterator end()
{
return _ht.End();
}
// 获取常量起始迭代器
const_iterator begin() const
{
return _ht.Begin();
}
// 获取常量结束迭代器
const_iterator end() const
{
return _ht.End();
}
// 下标操作符
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert({ key, V() });
return ret.first->second;
}
// 插入元素
pair<iterator, bool> insert(const pair<K,V>& kv)
{
return _ht.Insert(kv);
}
// 查找元素
iterator Find(const K& key)
{
return _ht.Find(key);
}
// 删除元素
bool Erase(const K& key)
{
return _ht.Erase(key);
}
private:
// 底层哈希表
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
};
}
#pragma once
#include"HashTable.h"
namespace sty
{
// unordered_set 模板类
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
// 从key中提取key的仿函数(直接返回key本身)
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
// 迭代器类型定义
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Const_Iterator const_iterator;
// 获取起始迭代器
iterator begin()
{
return _ht.Begin();
}
// 获取结束迭代器
iterator end()
{
return _ht.End();
}
// 获取常量起始迭代器
const_iterator begin() const
{
return _ht.Begin();
}
// 获取常量结束迭代器
const_iterator end() const
{
return _ht.End();
}
// 插入元素
pair<iterator, bool> insert(const K& key)
{
return _ht.Insert(key);
}
// 查找元素
iterator Find(const K& key)
{
return _ht.Find(key);
}
// 删除元素
bool Erase(const K& key)
{
return _ht.Erase(key);
}
private:
// 底层哈希表
hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
};
}