C++容器—unordered_map

1. 简介

#include template < class Key,// unordered_map::key_type class T,// unordered_map::mapped_type class Hash = std::hash,// unordered_map::hasher class Pred = std::equal_to,// unordered_map::key_equal class Alloc = std::allocator>// unordered_map::allocator_type > class unordered_map;

unordered_map 具有如下性质:
  • 唯一性:键是唯一的;
  • 无序性:键值对是无序存储的,元素被存储在桶中,如果两个元素拥有相同哈希值的键,则它们会被存储于同一桶中;
  • 具有常数时间复杂度(平均来说)的搜索、插入、删除操作。
2. 自定义键类型 如果键是自定义类型,则需要提供相应的哈希函数,来计算键的哈希值。
方法1:显式提供相应的模板参数
#include #include #include struct Key { std::string first; std::string second; }; struct KeyHash { std::size_t operator()(const Key& k) const { return std::hash()(k.first) ^ (std::hash()(k.second) << 1); } }; struct KeyEqual { bool operator()(const Key& lhs, const Key& rhs) const { return lhs.first == rhs.first && lhs.second == rhs.second; } }; int main() { Key k1{ "John", "Doe" }, k2{ "Mary", "Sue" }; std::unordered_map m = { { k1, "example"}, { k2, "another"} }; std::cout << m[k1] << '\n'; // example }

方法2:显式特化 std::hash<> 模板
template struct hash;

#include #include #include struct Foo { Foo(int val_) : val(val_) {} int val; // unordered_map::key_equal bool operator==(const Foo& rhs) const { return val == rhs.val; } }; namespace std { template<> struct hash { std::size_t operator()(const Foo& f) const { return std::hash{}(f.val); } }; }int main() { std::unordered_map m = { { Foo(1), "One"}, { 2, "Two"}, { 3, "Three"} }; std::cout << m[Foo(1)] << '\n'; // One }

3. 容器大小
std::unordered_map m; bool isEmpty = m.empty(); // Test whether container is empty size_t n = m.size(); // Return container size size_t limit = m.max_size(); // Return maximum size/* Sets the number of buckets in the container (bucket_count) to the most appropriate to contain at least 30 elements. */ m.reserve(30);

4. 访问元素
std::unordered_map m; m["Bakery"] = "Barbara"; // 存在时更新值;不存在时插入键值对 std::string v = m["Bakery"]; // 存在时返回对应的值;不存在时插入键值对(使用值类型的默认构造函数来创建值)m.at("Hello") = "World"; // 存在时更新值;不存在时抛出 out_of_range 异常 std::string v = m.at("Hello"); // 存在时返回对应的值;不存在时抛出 out_of_range 异常

5. 查找元素
std::unordered_map m = { {"mom", 5.4}, {"dad", 6.1}, {"bro", 5.9} }; auto it = m.find("mom"); if (it == m.end()) { std::cout << "not found"; } else { std::cout << "key=" << it->first << ", value="https://www.it610.com/article/<< it->second; }bool exists = m.contains("mom"); // 是否存在(C++20)

6. 插入元素 emplace:使用给定的实参原地构造元素,可以避免不必要的拷贝。只有不存在相应的键才会插入。
struct Person { std::string m_name; double m_salary; Person() = default; Person(const std::string& name, double salary) : m_name(name), m_salary(salary) {} }; int main() { std::unordered_map m; /* 返回值类型为 pair 其中,迭代器执行新插入的元素,或已存在的元素 bool 表示是否插入成功 */ auto p = m.emplace(1, Person(std::string("Mike"), 12345.6)); if (p.second) { std::cout << "插入成功\n"; } else { std::cout << "已存在,原值为:" << p.first->second.m_salary; } }

insert:只有不存在相应的键才会插入。
std::unordered_map m; /* 返回值类型为 pair 其中,迭代器执行新插入的元素,或已存在的元素 bool 表示是否插入成功 */ auto p = m.insert({ "sugar", 0.8 }); if (p.second) { std::cout << "插入成功\n"; } else { std::cout << "已存在,原值为:" << p.first->second; }

7. 删除元素
std::unordered_map m; m.erase("France"); // 删除指定键的元素,不存在时也没事auto it = m.find("France"); if (it != m.end()) { m.erase(it); // 删除指定位置的元素 }m.clear(); // 清空容器

8. 遍历容器 遍历元素
std::unordered_map m { { "Australia", "Canberra" }, { "U.S.", "Washington" }, { "France", "Paris" } }; for (auto it = m.begin(); it != m.end(); it++) { if (it->first[0] == 'U') { std::cout << it->first << "->" << it->second << '\n'; } }

【C++容器—unordered_map】遍历桶
std::unordered_map m { {"house","maison"}, {"apple","pomme"}, {"tree","arbre"}, {"book","livre"}, {"door","porte"}, {"grapefruit","pamplemousse"} }; size_t bucketCount = m.bucket_count(); std::cout << "bucket count: " << bucketCount << '\n'; for (size_t i = 0; i < bucketCount; i++) { std::cout << "bucket #" << i << " has " << m.bucket_size(i) << " elements.\n"; } std::cout << '\n'; for (size_t i = 0; i < bucketCount; i++) { std::cout << "bucket #" << i << " contains: "; for (auto it = m.begin(i); it != m.end(i); it++) { std::cout << "[" << it->first << ":" << it->second << "] "; } std::cout << '\n'; }

bucket count: 8 bucket #0 has 1 elements. bucket #1 has 1 elements. bucket #2 has 1 elements. bucket #3 has 1 elements. bucket #4 has 0 elements. bucket #5 has 1 elements. bucket #6 has 0 elements. bucket #7 has 1 elements.bucket #0 contains: [book:livre] bucket #1 contains: [door:porte] bucket #2 contains: [grapefruit:pamplemousse] bucket #3 contains: [house:maison] bucket #4 contains: bucket #5 contains: [tree:arbre] bucket #6 contains: bucket #7 contains: [apple:pomme]

    推荐阅读