In this tutorial, we will explore the unordered_map and unordered_multimap containers in C++. These are part of the Standard Template Library (STL) and are based on hash tables, providing average O(1) lookup times. Understanding these containers is crucial for efficient data management, especially when dealing with large datasets.
The unordered_map and unordered_multimap are associative containers that store elements formed by a combination of a key value and a mapped value, following a specific order. Unlike the ordered maps (map and multimap), which maintain elements in a sorted order based on keys, unordered maps do not guarantee any particular order. This makes them highly efficient for operations like insertion, deletion, and lookup, with an average time complexity of O(1).
These containers are particularly useful when you need fast access to data without the overhead of maintaining order. However, they come with trade-offs in terms of memory usage and potential performance degradation in worst-case scenarios.
An unordered_map is a container that stores elements formed by the combination of a key value and a mapped value, and which allows for fast retrieval of individual elements based on their keys. The order of elements is not guaranteed to be consistent across different runs of the program.
unordered_map.Let's see how to use an unordered_map:
1#include <iostream>2#include <unordered_map>34int main() {5std::unordered_map<std::string, int> ageMap;67// Inserting elements8ageMap["Alice"] = 30;9ageMap["Bob"] = 25;10ageMap["Charlie"] = 35;1112// Accessing elements13std::cout << "Age of Alice: " << ageMap["Alice"] << std::endl;14std::cout << "Age of Bob: " << ageMap["Bob"] << std::endl;1516// Checking if a key exists17if (ageMap.find("Charlie") != ageMap.end()) {18std::cout << "Charlie is in the map." << std::endl;19}2021return 0;22}
Age of Alice: 30 Age of Bob: 25 Charlie is in the map.
An unordered_multimap is similar to an unordered_map, but it allows for multiple elements with equivalent keys. This means that you can store multiple values associated with the same key.
unordered_multimap.Let's see how to use an unordered_multimap:
1#include <iostream>2#include <unordered_map>34int main() {5std::unordered_multimap<std::string, int> ageMap;67// Inserting elements8ageMap.insert({"Alice", 30});9ageMap.insert({"Bob", 25});10ageMap.insert({"Alice", 31}); // Duplicate key1112// Accessing elements13auto range = ageMap.equal_range("Alice");14for (auto it = range.first; it != range.second; ++it) {15std::cout << "Age of Alice: " << it->second << std::endl;16}1718return 0;19}
Age of Alice: 30 Age of Alice: 31
| Feature | unordered_map | map |
|---|---|---|
| Order | No guaranteed order | Sorted by key |
| Performance | Average O(1) for operations | Logarithmic O(log n) |
| Memory Usage | Potentially higher due to hash table | Lower |
| Use Case | Fast lookup, no order required | Ordered data, sorted access |
unordered_mapmapBoth unordered_map and unordered_multimap provide a bucket interface, which allows you to access the underlying hash table structure. This can be useful for advanced operations like rehashing or customizing the load factor.
Let's see how to use the bucket interface:
1#include <iostream>2#include <unordered_map>34int main() {5std::unordered_map<std::string, int> ageMap;67// Inserting elements8ageMap["Alice"] = 30;9ageMap["Bob"] = 25;10ageMap["Charlie"] = 35;1112// Getting the number of buckets13std::cout << "Number of buckets: " << ageMap.bucket_count() << std::endl;1415// Iterating over elements in a specific bucket16for (size_t i = 0; i < ageMap.bucket_count(); ++i) {17std::cout << "Bucket #" << i << ": ";18for (auto it = ageMap.begin(i); it != ageMap.end(i); ++it) {19std::cout << "{" << it->first << ", " << it->second << "} ";20}21std::cout << std::endl;22}2324return 0;25}
Number of buckets: 8
Bucket #0:
Bucket #1: {Charlie, 35}
Bucket #2:
Bucket #3: {Alice, 30}
Bucket #4:
Bucket #5:
Bucket #6: {Bob, 25}
Bucket #7:Let's create a practical example that demonstrates the use of unordered_map and unordered_multimap. We'll build a simple program that manages a collection of books, where each book has a title and multiple authors.
1#include <iostream>2#include <unordered_map>3#include <vector>45int main() {6std::unordered_map<std::string, int> bookPages;7std::unordered_multimap<std::string, std::string> authorBooks;89// Adding books10bookPages["The Great Gatsby"] = 180;11bookPages["To Kill a Mockingbird"] = 281;12bookPages["1984"] = 328;1314authorBooks.insert({"F. Scott Fitzgerald", "The Great Gatsby"});15authorBooks.insert({"Harper Lee", "To Kill a Mockingbird"});16authorBooks.insert({"George Orwell", "1984"});17authorBooks.insert({"Ernest Hemingway", "The Old Man and the Sea"});1819// Displaying books by page count20std::cout << "Books by page count:" << std::endl;21for (const auto& book : bookPages) {22std::cout << book.first << ": " << book.second << " pages" << std::endl;23}2425// Displaying books by author26std::cout << "27Books by author:" << std::endl;28for (const auto& author : authorBooks) {29std::cout << author.first << " wrote: " << author.second << std::endl;30}3132return 0;33}
Books by page count: The Great Gatsby: 180 pages To Kill a Mockingbird: 281 pages 1984: 328 pages Books by author: F. Scott Fitzgerald wrote: The Great Gatsby Harper Lee wrote: To Kill a Mockingbird George Orwell wrote: 1984 Ernest Hemingway wrote: The Old Man and the Sea
unordered_map: Fast lookup, no order guarantee, unique keys.unordered_multimap: Fast lookup, no order guarantee, multiple values per key.unordered_map when fast access is crucial and order is not important.map when maintaining a sorted order is necessary.In the next tutorial, we will explore unordered_set and unordered_multiset, which are unordered versions of the set containers. These containers provide similar performance benefits as unordered_map and unordered_multimap but for unique or multiple elements without associated values.
Stay tuned!