C++中unordered_map和unordered_set的使用
更新時間:2026年07月23日 09:46:14 作者:流星白龍
本文主要介紹了C++中unordered_map和unordered_set的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
1. unordered_set系列的使用
1.1 unordered_set和unordered_multiset參考文檔
1.2 unordered_set類的介紹
- unordered_set的聲明如下,Key就是unordered_set底層關鍵字的類型
- unordered_set默認要求Key支持轉換為整形,如果不支持或者想按自己的需求走可以自行實現(xiàn)支持將Key轉成整形的仿函數(shù)傳給第二個模板參數(shù)
- unordered_set默認要求Key支持比較相等,如果不支持或者想按自己的需求走可以自行實現(xiàn)支持將Key比較相等的仿函數(shù)傳給第三個模板參數(shù)
- unordered_set底層存儲數(shù)據(jù)的內存是從空間配置器申請的,如果需要可以自己實現(xiàn)內存池,傳給第四個參數(shù)。
- 一般情況下,我們都不需要傳后三個模板參數(shù)
- unordered_set底層是用哈希桶實現(xiàn),增刪查平均效率是 ,迭代器遍歷不再有序,為了跟set區(qū)分,所以取名unordered_set。O(1)
- 前面部分我們已經學習了set容器的使用,set和unordered_set的功能高度相似,只是底層結構不同,有一些性能和使用的差異,這里我們只講他們的差異部分。
// unordered_set模板聲明:一個不保證元素順序的集合容器
template <
class Key, // 鍵與值的類型(因為是集合,鍵就是值)
// 例如:unordered_set<int>, unordered_set<string>
class Hash = hash<Key>, // 哈希函數(shù)對象類型,用于計算元素的哈希值
// 默認使用標準庫的hash
class Pred = equal_to<Key>, // 判斷兩個鍵是否相等的函數(shù)對象類型
// 默認使用標準庫的equal_to
class Alloc = allocator<Key> // 內存分配器類型
// 默認使用標準分配器allocator
>
class unordered_set;
1.3 unordered_set和set的使用差異
- 查看文檔我們會發(fā)現(xiàn)unordered_set的支持增刪查且跟set的使用一模一樣,關于使用我們這里就不再贅述和演示了。
- unordered_set和set的第一個差異是對key的要求不同,set要求Key支持小于比較,而unordered_set要求Key支持轉成整形且支持等于比較,要理解unordered_set的這個兩點要求得后續(xù)我們結合哈希表底層實現(xiàn)才能真正理解,也就是說這本質是哈希表的要求。
- unordered_set和set的第二個差異是迭代器的差異,set的iterator是雙向迭代器,unordered_set是單向迭代器,其次set底層是紅黑樹,紅黑樹是二叉搜索樹,走中序遍歷是有序的,所以set迭代器遍歷是有序+去重。而unordered_set底層是哈希表,迭代器遍歷是無序+去重。
- unordered_set和set的第三個差異是性能的差異,整體而言大多數(shù)場景下,unordered_set的增刪查改更快一些,因為紅黑樹增刪查改效率是 ,而哈希表增刪查平均效率是 ,具體可以參看下面代碼的演示的對比差異。
// 插入函數(shù):插入元素到容器 // 參數(shù):待插入的值 // 返回:pair<迭代器,bool> // 迭代器指向插入位置或已存在元素位置 // bool為true表示插入成功,false表示已存在 pair<iterator,bool> insert(const value_type& val); // 刪除函數(shù):刪除指定key的元素 // 參數(shù):要刪除的key // 返回:刪除的元素個數(shù)(0表示元素不存在,1表示刪除成功) size_type erase(const key_type& k); // 查找函數(shù):查找指定key的元素 // 參數(shù):要查找的key // 返回:指向找到元素的迭代器,未找到返回end() iterator find(const key_type& k);
#include<unordered_set> // 無序集合容器
#include<unordered_map> // 無序映射容器
#include<set> // 有序集合容器
#include<iostream>
using namespace std;
int test_set2()
{
const size_t N = 1000000; // 測試數(shù)據(jù)量100萬
unordered_set<int> us; // 聲明無序集合
set<int> s; // 聲明有序集合
vector<int> v; // 存儲測試數(shù)據(jù)的vector
v.reserve(N); // 預留空間,避免動態(tài)擴容
srand(time(0)); // 隨機種子
// 生成測試數(shù)據(jù)
for (size_t i = 0; i < N; ++i)
{
//v.push_back(rand()); // N較大時重復值較多
v.push_back(rand()+i); // 加上i使重復值較少
//v.push_back(i); // 完全有序無重復
}
// 測試set的插入性能
size_t begin1 = clock();
for (auto e : v)
{
s.insert(e);
}
size_t end1 = clock();
cout << "set insert:" << end1 - begin1 << endl;
// 測試unordered_set的插入性能
size_t begin2 = clock();
us.reserve(N); // 預留空間,避免rehash
for (auto e : v)
{
us.insert(e);
}
size_t end2 = clock();
cout << "unordered_set insert:" << end2 - begin2 << endl;
// 測試set的查找性能
int m1 = 0; // 記錄查找成功次數(shù)
size_t begin3 = clock();
for (auto e : v)
{
auto ret = s.find(e);
if (ret != s.end()) // 找到元素
{
++m1;
}
}
size_t end3 = clock();
cout << "set find:" << end3 - begin3 << "->" << m1 << endl;
// 測試unordered_set的查找性能
int m2 = 0; // 記錄查找成功次數(shù)
size_t begin4 = clock();
for (auto e : v)
{
auto ret = us.find(e);
if (ret != us.end()) // 找到元素
{
++m2;
}
}
size_t end4 = clock();
cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << endl;
// 輸出實際插入數(shù)據(jù)量(因為有重復值,所以小于N)
cout << "插入數(shù)據(jù)個數(shù):" << s.size() << endl;
cout << "插入數(shù)據(jù)個數(shù):" << us.size() << endl << endl;
// 測試set的刪除性能
size_t begin5 = clock();
for (auto e : v)
{
s.erase(e);
}
size_t end5 = clock();
cout << "set erase:" << end5 - begin5 << endl;
// 測試unordered_set的刪除性能
size_t begin6 = clock();
for (auto e : v)
{
us.erase(e);
}
size_t end6 = clock();
cout << "unordered_set erase:" << end6 - begin6 << endl << endl;
return 0;
}
int main()
{
test_set2(); // 執(zhí)行性能測試
return 0;
}
1.4 unordered_map和map的使用差異
- 查看文檔我們會發(fā)現(xiàn)unordered_map的支持增刪查改且跟map的使用一模一樣,關于使用我們這里就不再贅述和演示了。
- unordered_map和map的第一個差異是對key的要求不同,map要求Key支持小于比較,而unordered_map要求Key支持轉成整形且支持等于比較,要理解unordered_map的這個兩點要求得后續(xù)我們結合哈希表底層實現(xiàn)才能真正理解,也就是說這本質是哈希表的要求。
- unordered_map和map的第二個差異是迭代器的差異,map的iterator是雙向迭代器,unordered_map是單向迭代器,其次map底層是紅黑樹,紅黑樹是二叉搜索樹,走中序遍歷是有序的,所以map迭代器遍歷是Key有序+去重。而unordered_map底層是哈希表,迭代器遍歷是Key無序+去重。
- unordered_map和map的第三個差異是性能的差異,整體而言大多數(shù)場景下,unordered_map的增刪查改更快一些,因為紅黑樹增刪查改效率是 ,而哈希表增刪查平均效率是 ,具體可以參看下面代碼的演示的對比差異。
// 插入函數(shù) // 參數(shù):要插入的鍵值對或元素值 // 返回:pair<迭代器,bool>組合 // 迭代器指向插入位置或已存在元素位置 // bool表示是否插入成功(true插入成功,false表示已存在) pair<iterator,bool> insert(const value_type& val); // 刪除函數(shù) // 參數(shù):要刪除元素的key // 返回:實際刪除的元素個數(shù) // 對于set/map返回0(不存在)或1(刪除成功) size_type erase(const key_type& k); // 查找函數(shù) // 參數(shù):要查找的key // 返回:指向找到元素的迭代器 // 如果沒找到返回end()迭代器 iterator find(const key_type& k); // map中的[]運算符重載 // 參數(shù):關鍵字key // 返回:key對應的value的引用 // 特點:如果key不存在則自動插入,value默認初始化 mapped_type& operator[](const key_type& k);
1.5 unordered_multimap/unordered_multiset
- unordered_multimap/unordered_multiset跟multimap/multiset功能完全類似,支持Key冗余。
- unordered_multimap/unordered_multiset跟multimap/multiset的差異也是三個方面的差異,key的要求的差異,iterator及遍歷順序的差異,性能的差異。
1.6 UnOrderedMap.h代碼實現(xiàn)
UnOrderedMap.h
#pragma once // 防止頭文件被重復包含
#include"HashTable.h" // 引入哈希表的實現(xiàn)
namespace bit
{
// unordered_map類模板,實現(xiàn)鍵值對的無序映射
template<class K, class V>
class unordered_map
{
// 仿函數(shù)類,用于從pair中提取key值
struct MapKeyOfT
{
// 重載()運算符,返回pair中的first成員(鍵值)
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
// 使用類型別名簡化迭代器類型的書寫
// 注意這里的模板參數(shù):
// K: 鍵類型
// pair<K,V>: 實際存儲的值類型(鍵值對)
// MapKeyOfT: 提取鍵的仿函數(shù)
typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::iterator iterator;
// 返回容器的起始迭代器
iterator begin()
{
return _ht.begin();
}
// 返回容器的結束迭代器
iterator end()
{
return _ht.end();
}
// 插入鍵值對
// 參數(shù)kv: 要插入的鍵值對
// 返回值: 插入是否成功
bool insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
private:
// 底層哈希表對象
// K: 鍵類型
// pair<K,V>: 存儲的值類型
// MapKeyOfT: 提取鍵的仿函數(shù)
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
};
}
1.7 UnOrderedSet.h代碼實現(xiàn)
UnOrderedSet.h
#pragma once // 防止頭文件被重復包含
#include"HashTable.h" // 引入哈希表的實現(xiàn)
namespace bit
{
// unordered_set類模板,實現(xiàn)無序集合
// 特點:不重復、無序、只存儲key
template<class K>
class unordered_set
{
// 仿函數(shù)類,用于返回key值本身
// 因為set只存儲key,所以key和value是同一個值
struct SetKeyOfT
{
// 重載()運算符,直接返回key
const K& operator()(const K& key)
{
return key;
}
};
public:
// 使用類型別名簡化迭代器類型的書寫
// 注意這里的模板參數(shù):
// K: 鍵類型
// K: 值類型(與鍵相同)
// SetKeyOfT: 提取鍵的仿函數(shù)
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator iterator;
// 返回容器的起始迭代器
iterator begin()
{
return _ht.begin();
}
// 返回容器的結束迭代器
iterator end()
{
return _ht.end();
}
// 插入元素
// 參數(shù)key: 要插入的值
// 返回值: 插入是否成功(如果元素已存在則返回false)
bool insert(const K& key)
{
return _ht.Insert(key);
}
private:
// 底層哈希表對象
// K: 鍵類型
// K: 值類型(與鍵相同)
// SetKeyOfT: 提取鍵的仿函數(shù)
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
到此這篇關于C++中unordered_map和unordered_set的使用的文章就介紹到這了,更多相關C++ unordered_map和unordered_set內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++基于字符串實現(xiàn)大數(shù)相乘問題的代碼詳解
在實際編程中,我們經常會遇到需要處理大整數(shù)的情況,由于編程語言中內置整數(shù)類型有其表示范圍的限制,當需要處理的整數(shù)超出這些范圍時,就不能直接使用內置類型進行計算,所以本文給大家介紹了相關的解決方法,需要的朋友可以參考下2025-03-03
Linux?C/C++?timeout命令實現(xiàn)運行具有時間限制功能
inux?timeout命令的一個屬性是時間限制。可以為任何命令設置時間限制。如果時間到期,命令將停止執(zhí)行,這篇文章主要介紹了Linux?C/C++?timeout命令實現(xiàn)(運行具有時間限制),需要的朋友可以參考下2023-02-02

