C++ STL中实现容器映射主要依赖std::map和std::unordered_map,前者基于红黑树,保证按键有序,操作复杂度为O(log N),适合需要顺序访问或范围查询的场景;后者基于哈希表,平均操作复杂度为O(1),性能更高但不保证顺序,适用于对查询速度要求高且无需排序的场合。选择时需权衡有序性、性能和内存开销。自定义类型作键时,std::map需重载operator<或提供比较器,std::unordered_map则需特化std::hash并重载operator==以确保正确哈希和比较。此外,STL还提供std::multimap和std::unordered_multimap支持一对多映射,或可通过排序vector结合二分查找实现静态数据的高效映射。

在C++的STL中,要实现容器的映射功能,我们主要依赖于
std::map
std::unordered_map
实现容器映射,最直接的办法就是使用STL提供的
std::map
std::unordered_map
std::map
std::map
std::map
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> student_scores;
// 插入元素
student_scores["Alice"] = 95;
student_scores["Bob"] = 88;
student_scores.insert({"Charlie", 92}); // 另一种插入方式
// 查找元素
if (student_scores.count("Alice")) {
std::cout << "Alice's score: " << student_scores["Alice"] << std::endl;
}
// 遍历元素 (按键排序)
for (const auto& pair : student_scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 更新元素
student_scores["Bob"] = 90;
std::cout << "Bob's updated score: " << student_scores["Bob"] << std::endl;
return 0;
}而
std::unordered_map
立即学习“C++免费学习笔记(深入)”;
#include <iostream>
#include <unordered_map>
#include <string>
int main() {
std::unordered_map<std::string, int> student_scores;
// 插入元素
student_scores["Alice"] = 95;
student_scores["Bob"] = 88;
student_scores.insert({"Charlie", 92});
// 查找元素
auto it = student_scores.find("Bob");
if (it != student_scores.end()) {
std::cout << "Bob's score: " << it->second << std::endl;
}
// 遍历元素 (无序)
std::cout << "Unordered map elements:" << std::endl;
for (const auto& pair : student_scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}选择哪个,就看你对顺序有没有要求,以及对性能的侧重点了。
在我看来,这两种映射容器的选择,其实是C++编程中一个很经典的权衡问题,没有绝对的“最好”,只有“最适合”。
首先,我们得明白它们的核心差异:
std::map
std::map
std::map
std::unordered_map
std::unordered_map
std::map
std::unordered_map
std::map
所以,我的经验是:
std::map
std::unordered_map
std::unordered_map
std::map
当我们要用自定义的类或结构体作为
std::map
std::unordered_map
int
std::string
对于
std::map
operator<
#include <iostream>
#include <map>
#include <string>
struct Point {
int x;
int y;
// 重载小于运算符,实现严格弱序
bool operator<(const Point& other) const {
if (x != other.x) {
return x < other.x;
}
return y < other.y;
}
// 为了方便打印
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
int main() {
std::map<Point, std::string> point_names;
point_names[{1, 2}] = "Top-Left";
point_names[{3, 1}] = "Bottom-Right";
point_names[{1, 1}] = "Center";
for (const auto& pair : point_names) {
std::cout << "Point " << pair.first << " is " << pair.second << std::endl;
}
// 输出会按Point的定义顺序:(1,1), (1,2), (3,1)
return 0;
}如果没有重载
operator<
std::map
std::map<Point, std::string, MyPointComparer>
对于
std::unordered_map
std::size_t
operator==
哈希函数通常通过特化
std::hash
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional> // for std::hash
struct CustomKey {
int id;
std::string name;
// 1. 重载相等运算符
bool operator==(const CustomKey& other) const {
return id == other.id && name == other.name;
}
// 为了方便打印
friend std::ostream& operator<<(std::ostream& os, const CustomKey& k) {
return os << "{" << k.id << ", " << k.name << "}";
}
};
// 2. 为 CustomKey 特化 std::hash
namespace std {
template <>
struct hash<CustomKey> {
std::size_t operator()(const CustomKey& k) const {
// 一个简单的哈希组合方法,通常会用 boost::hash_combine 或类似技术
// 这里为了示例,简单组合
std::size_t h1 = std::hash<int>{}(k.id);
std::size_t h2 = std::hash<std::string>{}(k.name);
return h1 ^ (h2 << 1); // 简单的哈希组合
}
};
}
int main() {
std::unordered_map<CustomKey, double> data_map;
data_map[{101, "Apple"}] = 1.99;
data_map[{203, "Banana"}] = 0.79;
data_map[{101, "Apple"}] = 2.05; // 会更新已有值
std::cout << "Value for {101, Apple}: " << data_map[{101, "Apple"}] << std::endl;
for (const auto& pair : data_map) {
std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
}
return 0;
}哈希函数的质量至关重要。一个好的哈希函数应该能将不同的键尽可能均匀地分布到不同的哈希值上,减少冲突,从而保证
std::unordered_map
unordered_map
除了
std::map
std::unordered_map
一个很常见的变种是一对多映射,即一个键可以对应多个值。STL提供了
std::multimap
std::unordered_multimap
std::map
std::unordered_map
equal_range
#include <iostream>
#include <map>
#include <string>
int main() {
std::multimap<std::string, std::string> student_courses;
student_courses.insert({"Alice", "Math"});
student_courses.insert({"Bob", "Physics"});
student_courses.insert({"Alice", "History"}); // Alice 有多门课
student_courses.insert({"Charlie", "Chemistry"});
// 查找 Alice 的所有课程
auto range = student_courses.equal_range("Alice");
std::cout << "Alice's courses:" << std::endl;
for (auto it = range.first; it != range.second; ++it) {
std::cout << "- " << it->second << std::endl;
}
// 遍历所有元素
std::cout << "\nAll student courses:" << std::endl;
for (const auto& pair : student_courses) {
std::cout << pair.first << " -> " << pair.second << std::endl;
}
return 0;
}另一种不太直接但有时有效的“映射”方式,特别是在键空间有限且连续、或者数据量相对较小但需要极高查询速度时,可以考虑使用 std::vector
std::pair
std::map
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // For std::sort and std::lower_bound
struct DataEntry {
int id;
std::string value;
bool operator<(const DataEntry& other) const {
return id < other.id;
}
};
int main() {
std::vector<DataEntry> data = {
{3, "Banana"},
{1, "Apple"},
{5, "Cherry"}
};
// 排序,使其可以进行二分查找
std::sort(data.begin(), data.end());
// 查找 ID 为 3 的元素
int target_id = 3;
auto it = std::lower_bound(data.begin(), data.end(), DataEntry{target_id, ""});
if (it != data.end() && it->id == target_id) {
std::cout << "Found ID " << target_id << ": " << it->value << std::endl;
} else {
std::cout << "ID " << target_id << " not found." << std::endl;
}
return 0;
}这种方式在数据量固定且不常变动时,可以避免
std::map
此外,如果你需要一个非常稀疏的整数到值的映射,并且键的范围可能非常大但实际使用的键很少,有时可以考虑使用
std::vector
std::map<int, T>
std::vector<T>
std::array<T, N>
总之,STL提供了丰富的工具箱,关键在于理解它们的底层机制和性能特性,然后根据具体的应用场景和需求做出最合适的选择。
以上就是C++如何在STL中实现容器映射功能的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号