C++11中std::unordered_map的使用

本文深入探讨了C++标准库中的unordered_map容器,包括其内部实现、性能特点、应用场景以及与map容器的区别。通过多个实例展示了如何使用unordered_map进行数据存储、检索、更新等常见操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity. Internally, the elements are not sorted in any particular order,but organized into buckets. Which bucket an element is placed into depends entirely on the hash of its key. This allows fast access to individual elements, since once the hash is computed, it refers to the exact bucket the element is placed into.

unordered_map containers are faster than map containers to access individual elements by their key, although they are generally less efficient for range iteration through a subset of their elements.

unordered_map's generally use more memory. A map just has a few house-keeping pointers then memory for each object. Contrarily, unordered_map's have a big array (these can get quite big in some implementations) and then additional memory for each object. If you need to be memory-aware, a map should prove better, because it lacks the large array.

unordered_map is an associated container that stores elements formed by combination of key value and a mapped value. The key value is used to uniquely identify the element and mapped value is the content associated with the key. Both key and value can be of any type predefined or user-defined. Internally unordered_map is implemented using Hash Table,the key provided to map are hashed into indices of hash table that is why performance of data structure depends on hash function a lot but on an average the cost of look-up from hash table is O(1). In worst case unordered_map may require O(n) time but practically it is much faster and outperforms tree based maps.

std::map对应的数据结构是红黑树。红黑树是一种近似于平衡的二叉查找树,里面的数据是有序的。在红黑树上做查找、插入、删除操作的时间复杂度为O(logN)。而std::unordered_map对应哈希表,哈希表的特点就是查找效率高,时间复杂度为常数级别O(1), 而额外空间复杂度则要高出许多。所以对于需要高效率查询的情况,使用std::unordered_map容器,但是std::unordered_map对于迭代器遍历效率并不高。而如果对内存大小比较敏感或者数据存储要求有序的话,则可以用std::map容器。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "unordered_map.hpp"
#include <iostream>
#include <string>
#include <unordered_map>

//////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/container/unordered_map
int test_unordered_map1()
{
	// Create an unordered_map of three strings (that map to strings)
	std::unordered_map<std::string, std::string> u = {
			{ "RED", "#FF0000" },
			{ "GREEN", "#00FF00" },
			{ "BLUE", "#0000FF" }
	};

	// Iterate and print keys and values of unordered_map
	for (const auto& n : u) {
		std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
	}

	// Add two new entries to the unordered_map
	u["BLACK"] = "#000000";
	u["WHITE"] = "#FFFFFF";

	// Output values by key
	std::cout << "The HEX of color RED is:[" << u["RED"] << "]\n";
	std::cout << "The HEX of color BLACK is:[" << u["BLACK"] << "]\n";

	std::cout << "The u's size: " << u.size() << std::endl;

	return 0;
}

/////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/unordered_map/unordered_map/at/
typedef std::unordered_map<std::string, std::string> stringmap;

stringmap merge(stringmap a, stringmap b) {
	stringmap temp(a); temp.insert(b.begin(), b.end()); return temp;
}

int test_unordered_map2()
{
	////////// at/size
	std::unordered_map<std::string, int> mymap = { { "Mars", 3000 }, { "Saturn", 60000 }, { "Jupiter", 70000 } };

	mymap.at("Mars") = 3396;
	mymap.at("Saturn") += 272;
	mymap.at("Jupiter") = mymap.at("Saturn") + 9638;

	for (auto& x : mymap) {
		std::cout << x.first << ": " << x.second << std::endl;
	}

	std::cout << "mymap.size() is " << mymap.size() << std::endl;

	/////////// begin
	std::unordered_map<std::string, std::string> mymap2 = { { "Australia", "Canberra" }, { "U.S.", "Washington" }, { "France", "Paris" } };

	std::cout << "mymap2 contains:";
	for (auto it = mymap2.begin(); it != mymap2.end(); ++it)
		std::cout << " " << it->first << ":" << it->second;
	std::cout << std::endl;

	std::cout << "mymap2's buckets contain:\n";
	for (unsigned i = 0; i < mymap2.bucket_count(); ++i) {
		std::cout << "bucket #" << i << " contains:";
		for (auto local_it = mymap2.begin(i); local_it != mymap2.end(i); ++local_it)
			std::cout << " " << local_it->first << ":" << local_it->second;
		std::cout << std::endl;
	}

	////////////// bucket
	std::unordered_map<std::string, std::string> mymap3 = {
			{ "us", "United States" },
			{ "uk", "United Kingdom" },
			{ "fr", "France" },
			{ "de", "Germany" }
	};

	for (auto& x : mymap3) {
		std::cout << "Element [" << x.first << ":" << x.second << "]";
		std::cout << " is in bucket #" << mymap3.bucket(x.first) << std::endl;
	}

	/////////////// count
	std::unordered_map<std::string, double> mymap4 = {
			{ "Burger", 2.99 },
			{ "Fries", 1.99 },
			{ "Soda", 1.50 } };

	for (auto& x : { "Burger", "Pizza", "Salad", "Soda" }) {
		if (mymap4.count(x)>0)
			std::cout << "mymap4 has " << x << std::endl;
		else
			std::cout << "mymap4 has no " << x << std::endl;
	}

	///////////////// erase
	std::unordered_map<std::string, std::string> mymap5;

	// populating container:
	mymap5["U.S."] = "Washington";
	mymap5["U.K."] = "London";
	mymap5["France"] = "Paris";
	mymap5["Russia"] = "Moscow";
	mymap5["China"] = "Beijing";
	mymap5["Germany"] = "Berlin";
	mymap5["Japan"] = "Tokyo";

	// erase examples:
	mymap5.erase(mymap5.begin());      // erasing by iterator
	mymap5.erase("France");             // erasing by key
	mymap5.erase(mymap5.find("China"), mymap5.end()); // erasing by range

	// show content:
	for (auto& x : mymap5)
		std::cout << x.first << ": " << x.second << std::endl;

	////////////////////// find
	std::unordered_map<std::string, double> mymap6 = {
			{ "mom", 5.4 },
			{ "dad", 6.1 },
			{ "bro", 5.9 } };

	std::string input;
	std::cout << "who? ";
	getline(std::cin, input);

	std::unordered_map<std::string, double>::const_iterator got = mymap6.find(input);

	if (got == mymap6.end())
		std::cout << "not found";
	else
		std::cout << got->first << " is " << got->second;

	std::cout << std::endl;

	//////////////////// insert
	std::unordered_map<std::string, double>
		myrecipe,
		mypantry = { { "milk", 2.0 }, { "flour", 1.5 } };

	std::pair<std::string, double> myshopping("baking powder", 0.3);

	myrecipe.insert(myshopping);                        // copy insertion
	myrecipe.insert(std::make_pair<std::string, double>("eggs", 6.0)); // move insertion
	myrecipe.insert(mypantry.begin(), mypantry.end());  // range insertion
	myrecipe.insert({ { "sugar", 0.8 }, { "salt", 0.1 } });    // initializer list insertion

	std::cout << "myrecipe contains:" << std::endl;
	for (auto& x : myrecipe)
		std::cout << x.first << ": " << x.second << std::endl;

	std::cout << std::endl;

	//////////////////// =
	stringmap first = { { "AAPL", "Apple" }, { "MSFT", "Microsoft" } };  // init list
	stringmap second = { { "GOOG", "Google" }, { "ORCL", "Oracle" } };   // init list
	stringmap third = merge(first, second);                      // move
	first = third;                                    // copy

	std::cout << "first contains:";
	for (auto& elem : first) std::cout << " " << elem.first << ":" << elem.second;
	std::cout << std::endl;

	return 0;
}

//////////////////////////////////////////////////////
// reference: http://www.geeksforgeeks.org/unordered_map-in-stl-and-its-applications/
int test_unordered_map3()
{
	// key will be of string type and mapped value will be of double type
	std::unordered_map<std::string, double> umap;

	// inserting values by using [] operator
	umap["PI"] = 3.14;
	umap["root2"] = 1.414;
	umap["root3"] = 1.732;
	umap["log10"] = 2.302;
	umap["loge"] = 1.0;

	// inserting value by insert function
	umap.insert(std::make_pair("e", 2.718));

	std::string key = "PI";

	// If key not found in map iterator to end is returned
	if (umap.find(key) == umap.end()) {
		std::cout << key << " not found\n\n";
	} else {// If key found then iterator to that key is returned
		std::cout << "Found " << key << "\n\n";
	}

	key = "lambda";
	if (umap.find(key) == umap.end())
		std::cout << key << " not found\n";
	else
		std::cout << "Found " << key << std::endl;

	//  iterating over all value of umap
	std::unordered_map<std::string, double>::iterator itr;
	std::cout << "\nAll Elements : \n";
	for (itr = umap.begin(); itr != umap.end(); itr++) {
		// itr works as a pointer to pair<string, double> type itr->first stores the key part
		// and itr->second stroes the value part
		std::cout << itr->first << "  " << itr->second << std::endl;
	}

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

### C++ 中 `std::unordered_map` 的使用方法 #### 创建和初始化 `std::unordered_map` `std::unordered_map` 是一种关联容器,它存储键值对并允许快速查找。创建一个简单的 `std::unordered_map` 可以通过以下方式完成: ```cpp #include <iostream> #include <unordered_map> int main() { // 定义一个字符串到整数的映射 std::unordered_map<std::string, int> ageMap; // 插入元素 ageMap["Alice"] = 30; ageMap.insert(std::make_pair("Bob", 25)); // 输出元素数量 std::cout << "Size of map: " << ageMap.size() << "\n"; } ``` 此代码展示了如何定义、插入以及获取 `std::unordered_map` 大小的方法[^1]。 #### 访问元素 访问 `std::unordered_map` 中已有的元素可以通过下标操作符实现;如果指定的键不存在,则会自动插入一个新的默认构造的值。 ```cpp // 获取 Alice 的年龄 if (ageMap.find("Alice") != ageMap.end()) { std::cout << "Alice's age is " << ageMap["Alice"] << "\n"; } // 尝试获取 Charlie 的年龄(未存在) auto it = ageMap.find("Charlie"); if (it == ageMap.end()) { std::cout << "Charlie not found\n"; } else { std::cout << "Charlie's age is " << (*it).second << "\n"; } ``` 上述例子说明了安全地检查是否存在某个键,并尝试读取其对应的值的方式。 #### 遍历 `std::unordered_map` 遍历整个哈希表可以利用迭代器来完成,下面是一个完整的示例程序展示如何打印所有的键值对: ```cpp for (const auto& pair : ageMap) { std::cout << "{" << pair.first << ": " << pair.second << "}\n"; } ``` 这段代码片段提供了一种简洁的方式来枚举所有存储于 `std::unordered_map` 内部的数据项。 #### 删除元素 删除单个元素或清空整个集合也是常见的需求之一,在这里给出相应的语法糖: ```cpp // 移除 Bob 这条记录 ageMap.erase("Bob"); // 清理全部数据 ageMap.clear(); ``` 这些语句分别演示了移除特定键所对应项目及清除所有项目的做法。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值