std::unordered_map
是 C++ 标准库提供的哈希表实现,用于存储键-值对。以下是 std::unordered_map
的基本用法:
包含头文件
#include <unordered_map>
创建unordered_map对象
创建一个 std::unordered_map
对象,指定键和值的类型。
unordered_map<string, int> ages;
插入键值对
ages.insert(make_pair("Allen",15));
ages["Bob"] = 16;
以上两种方式可以向unordered_map插入键值对。
访问键值
cout << ages["Allen"];
cout << ages["Cindy"];
注意,如果键值不存在,如"Cindy",会在哈希表中新建一个键值对,值会初始化为默认值。int会初始化为0。
查询键值是否存在
使用find函数
if(ages.find("xxx")==ages.end()){
cout << "Not in map";
}
else{
cout << ages.find("xxx")->second;
}
find()函数返回一个unordered_map的迭代器,如果存在,返回指向该键值的迭代器;如果不存在,则返回ages.end()的尾部迭代器。
unordered_map的迭代器
迭代方式: std::unordered_map
中的元素是无序的,因此迭代元素的顺序是不确定的。你不能依赖迭代器按照特定的顺序遍历元素。
删除键值对
ages.erase("Bob");
遍历
for(auto item=ages.begin();item!=ages.end();item++){
cout << item->second;
}
在C++11后的版本中可以简化成
for(auto item : ages){
cout << item.first << " is " << item.second;
}
注
注意两种遍历方式中item对元素的访问方式不同。因为,在范围循环的情况下(for(auto item:ages)),item的类型是一个pair对象,pair<const Key, T>
,其中 Key
是键类型(string
),T
是值类型(int
)。所以可以通过.first和.second直接访问pair的元素。
而在迭代器循环的情况下,item返回的是unordered_map的迭代器,迭代器类似一个指向键值对的指针,所以需要通过->方法访问元素的值。
unordered_set
是 C++ 标准库中的关联容器,它是一种集合,用于存储一组唯一的元素。与 std::set
不同,std::unordered_set
内部使用哈希表来实现,这使得元素的查找、插入和删除操作非常高效。
与unordered_map的区别在于set只保存键的值,而map保存键值对。
-
包含头文件: 要使用
std::unordered_set
,首先需要包含正确的头文件:#include <unordered_set>
-
创建
std::unordered_set
实例: 创建一个std::unordered_set
对象,并指定元素的类型。例如,以下是一个存储整数的std::unordered_set
:std::unordered_set<int> numbers;
-
插入元素: 使用
insert
函数来插入元素到std::unordered_set
中:numbers.insert(10); numbers.insert(20); numbers.insert(30);
由于
std::unordered_set
存储的是唯一元素,重复的插入会被忽略。 -
查找元素: 使用
find
函数来查找元素是否存在:auto it = numbers.find(20); if (it != numbers.end()) { std::cout << "20 found in the set." << std::endl; } else { std::cout << "20 not found in the set." << std::endl; }
-
删除元素: 使用
erase
函数来删除元素:numbers.erase(10);
-
遍历
std::unordered_set
: 使用范围循环或迭代器来遍历集合中的元素:使用范围循环(C++11 及以后版本):
for (const auto& element : numbers) { std::cout << element << " "; }
使用迭代器:
for (auto it = numbers.begin(); it != numbers.end(); ++it) { std::cout << *it << " "; }
-
无序性:
std::unordered_set
中的元素是无序的,它们不会按照特定顺序存储。
std::unordered_set
提供了高效的元素查找、插入和删除操作,通常在需要存储一组唯一元素且不关心元素的顺序时使用。然而,需要注意的是,键类型必须支持哈希函数,因此如果使用自定义类型作为元素,需要提供相应的哈希函数。
为什么自定义类型需要提供哈希函数
unordered_map
使用哈希表来实现数据的存储和查找。哈希表的核心思想是通过哈希函数将键映射到表中的某个位置(桶),然后在该位置查找或插入值。哈希函数的质量对哈希表的性能和正确性有重要影响。
当你使用 std::unordered_map
存储自定义结构作为键时,你需要提供一个自定义的哈希函数,以确保以下几点:
-
一致性: 相同的键应该始终映射到相同的桶。这是哈希表正确性的基本要求。如果不提供自定义哈希函数,C++ 标准库会使用默认的哈希函数,但这对于自定义结构可能不是合适的。
-
均匀性: 好的哈希函数应该使键均匀分布到桶中,以减少哈希冲突的概率。如果多个键映射到同一个桶,性能可能会受到影响。自定义哈希函数可以根据键的属性和分布特点来优化哈希映射。
-
快速性: 自定义哈希函数应该具有高效的计算速度,以不影响哈希表的性能。过于复杂的哈希函数可能会降低性能。
-
唯一性: 如果自定义结构的相等性比较不足以确定键是否相等,哈希函数可以提供额外的信息来区分不同的键。