简介#
什么是 Map?#
- Map 是一种容器,用于存储键值对。它允许你通过一个“键”(Key)来快速查找对应的“值”(Value)。
- 类比:就像一本字典,单词是键,定义是值。
std::map vs std::unordered_map#
- std::map (有序映射):
- 底层结构:红黑树(一种自平衡二叉搜索树)。
- 特点:元素按键的顺序自动排序。
- 复杂度:查找、插入、删除均为 O(logn)。
- std::unordered_map (无序映射):
- 底层结构:哈希表(Hash Table)。
- 特点:元素没有特定顺序。
- 复杂度:平均情况下查找速度为 O(1),通常比
std::map快,除非哈希冲突严重。
代码演示:基础用法#
- 展示如何定义
std::map<std::string, CityRecord>。 - 使用
operator[]进行赋值:map["Berlin"] = CityRecord { ... };。 - 注意:如果访问一个不存在的键,
operator[]会自动创建一个默认构造的对象并插入。
迭代与访问#
- 演示如何使用
for (auto& [key, value] : map)(C++17 结构化绑定)遍历 Map。 - 解释了老式迭代器用法:
it->first是键,it->second是值。
性能取舍与选择建议#
- 优先选择
std::unordered_map:如果你只需要快速查找,不需要元素有序,那么无序映射通常性能更优。 - 选择
std::map的场景:当你需要遍历时保持特定顺序,或者需要使用类似lower_bound的区间查找功能时。
复杂键的处理#
- 讲解了如果使用自定义类作为键,
std::map需要该类重载<运算符,而std::unordered_map则需要提供哈希函数。
#ifdef LY_EP100
#include <iostream>
#include <map>
#include <unordered_map>
#include <string>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longitude;
};
std::ostream& operator<<(std::ostream& stream,
const CityRecord& cityRecord)
{
std::cout << "Name: " << cityRecord.Name << ","
<< "Population: " << cityRecord.Population << ","
<< "Latitude: " << cityRecord.Latitude << ","
<< "Longitude: " << cityRecord.Longitude << std::endl;
return stream;
}
namespace std {
template<>
struct hash<CityRecord>
{
size_t operator()(const CityRecord& key)
{
//hash<std::string>()这是调用构造函数,
//然后构造了std::hash<CityRecord> 类型的对象,
//之后调用了该对象的()重载方法
return hash<std::string>()(key.Name);
}
};
}
int main()
{
//计算City
CityRecord cityRecord = { "name1",10000,2.3,4.5 };
auto hashcode=std::hash<CityRecord>()(cityRecord);
if (hashcode)
{
std::cout << "hashcode: " << hashcode << std::endl;
std::cout << cityRecord << std::endl;
}
std::cin.get();
return 0;
}
#endif模板特化#
1. 什么是普通模板?(工厂的模具)#
模板就像一个通用的模具。比如你想写一个 print 函数,不管是 int、float 还是 string 都能用:
template<typename T>
void print(T value) {
std::cout << "通用打印: " << value << std::endl;
}当你调用 print(10) 或 print("Hello") 时,编译器会根据这个模具自动生成对应的代码。
2. 什么是模板特化?(给特殊客人的定制版)#
有时候,通用的模具对某些特定类型不好使。
比如,你想打印 bool 类型。通用的模具会打印 1 或 0。但你觉得这样不直观,你希望打印 bool 时输出 "Yes" 或 "No"。
这时候你就需要特化(Specialization)—— 告诉编译器:“如果是别的类型,按通用模具来;如果是 bool 类型,请按我专门写的这套逻辑来。”
// 1. 通用模板 (Primary Template)
template<typename T>
struct Printer {
void print(T value) { std::cout << value << std::endl; }
};
// 2. 全特化 (Full Specialization) —— 专门针对 bool 类型
template<> // 注意:这里尖括号空了,因为类型已经定死在下面了
struct Printer<bool> {
void print(bool value) {
std::cout << (value ? "Yes" : "No") << std::endl;
}
};