unordered_map使用笔记
- 在使用unordered_map和map的过程中,一直将map当做是排序的,unordered_map是不排序,但是按照插入的顺序记录的。知道一次使用发现和自己预期的不一致。发现unordered_map是不排序,但也不是按照插入顺序记录的。
几个例子
用例1: 只是插入数据, 数据按照插入顺序排序了
#include <string>
#include <unordered_map>
#include <iostream>
using namespace std;
int main()
{
std::unordered_map<std::string, int> mm;
mm.insert(pair<string, int>("a", 1));
mm.insert(pair<string, int>("b", 1));
mm.insert(pair<string, int>("c", 1));
mm.insert(pair<string, int>("d", 1));
mm.insert(pair<string, int>("e", 1));
for (auto& item : mm) {
cout << item.first << " " << item.second << endl;
}
cout << "start maporder" << endl;
return 0;
}
- 输出结果
用例2:只是插入数据, 数据没有按照插入顺序排序
#include <string>
#include <unordered_map>
#include <iostream>
using namespace std;
int main()
{
std::unordered_map<std::string, int> mm;
mm.insert(pair<string, int>("abcsadad", 1));
mm.insert(pair<string, int>("badsfsafa", 1));
mm.insert(pair<string, int>("cfgfdg", 1));
mm.insert(pair<string, int>("dgfdsgfa", 1));
mm.insert(pair<string, int>("esd", 1));
for (auto& item : mm) {
cout << item.first << endl;
}
return 0;
}
- 输出结果
用例3: 中间删除在插入数据
#include <string>
#include <unordered_map>
#include <iostream>
using namespace std;
int main()
{
std::unordered_map<std::string, int> mm;
mm.insert(pair<string, int>("abcsadad", 1));
mm.insert(pair<string, int>("badsfsafa", 1));
mm.insert(pair<string, int>("cfgfdg", 1));
mm.insert(pair<string, int>("dgfdsgfa", 1));
mm.insert(pair<string, int>("esd", 1));
mm.erase("cfgfdg");
mm.insert(pair<string, int>("fda", 1));
for (auto& item : mm) {
cout << item.first << endl;
}
return 0;
}
- 输入结果
说明
- 三个测试用例的首字符都是按照abc顺序写入的,但是每一个排序都不一样。
- 原因如下:
unordered_map 是一种哈希表实现的关联容器,它以无序的方式存储键值对,其内部结构依赖于哈希函数、等价关系(用于处理键的相等性判断)以及可能的冲突解决策略(如开放寻址法或链地址法)。
当unordered_map 插入一个键值对时,C++ 标准库会执行以下步骤:
计算哈希值:首先,使用哈希函数对键(Key)进行计算,得到一个哈希值。哈希函数设计的目标是尽可能地将不同的键映射到哈希表的不同位置,以减少冲突。
定位桶:根据哈希值,找到对应的哈希桶(Bucket)。哈希表由一系列哈希桶组成,每个桶可以包含零个或多个元素。通常情况下,哈希值会被映射到桶数组的索引。
处理冲突:如果所定位的桶已经存在其他元素(即发生了哈希冲突),则采用特定的冲突解决策略(如链地址法)将新元素添加到该桶内。在链地址法中,桶内的元素是以某种链表形式链接在一起的。新元素被插入到链表的适当位置,这一步骤并不保证新元素在链表中的具体位置(前、中、后)。
综上所述,std::unordered_map 插入元素的位置取决于哈希函数、哈希表当前的状态(已有的键值对分布)以及哈希冲突的处理结果。插入操作本身并不保证任何特定的插入顺序,也不会默认将元素插入到“前面”或“后面”。如果您需要保持元素的插入顺序,应考虑使用 std::map(有序,基于红黑树实现,按键排序)或 std::unordered_multimap(无序,基于哈希表实现,但允许键重复且保持插入顺序,C++17起)。
如果观察到的现象表明 unordered_map 插入元素似乎总是在“前面”,那可能是巧合,或者数据集、哈希函数、哈希表大小等因素导致了这种看似有规律的插入位置。但这并非 unordered_map 的行为规范,不应依赖于这种偶然现象。