【C++】std::pair 作为 std::unordered_map 的 key

  unordered_map 是 C++ 11 中新加入的容器,和没有标准化的 hash_map 一个意思,使用 hash 表作为底层数据结构,那么对于键值就需要有 hash function 计算出对应的 hash 值了。
  对于内置函数,hash function 是自带的,不需要显示指定,如下所示,使用 int、string 作为键值是可以的,但是使用 vector 和 pair 是不行,提示就是 'The C++ Standard doesn’t provide a hash for this type."。

#include <unordered_map>
#include <vector>
using namespace std;
int main() {
	unordered_map<int, int> mmp;
	unordered_map<string, int> mmp1;
	
	// The C++ Standard doesn't provide a hash for this type.
	unordered_map<pair<int, int>, int> mmp2;	// Error
	unordered_map<vector<int>, int> mmp2;		// Error
}

  那么这个 hsah function 是在哪里呢,跳到 unordered_map 定义的地方,可以看到,构造函数有很多中,unordered_map<string, int> mmp1; 这种形式进行构造的话,应该是下图这样的方式,也就是第一个模板参数是键值,第二个末班参数是,第三个模板参数是hash function(hash<_Kty>),第四个模板参数是相等的比较函数(或者说表现为函数的对象),最后一个是分配器。

  官方的五个参数的注释如下:

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

  我们可以通过 unordered_map<int, int>::hasher hs = mmp.hash_function(); 的方式得到 unordered_map 对于不同的键值计算出的 hash 值,也可以直接利用 hash()(1) 的方式进行调用,如下所示:

int main() {
	unordered_map<int, int> mmp;
	unordered_map<int, int>::hasher hs = mmp.hash_function();
	
	cout << hs(1) << endl;						// 4218009092	
	cout << hs(2) << endl;						// 3958272823
	cout << hash<int>()(1) << endl;				// 4218009092, equal = hs(1)
	cout << hash<string>()("abc") << endl;		// 440920331
	cout << hash<float>()(3.1415926) << endl;	// 812821127
	cout << hash<double>()(3.1415926) << endl;	// 2306040251
}

  我们可以调到 hash 这个结构的定义部分,如下图,对于基础类型,都给出了对应的模板特化,也可以看到上边编译错误时报错的地方。

  所以如果对于自定义类型,或者 hash 这个结构没有提供模板特化的数据类型,那就需要自己定义了,最简单的方法就是:

struct pair_hash {
	template<class T1, class T2>
	std::size_t operator() (const std::pair<T1, T2>& p) const {
		auto h1 = std::hash<T1>{}(p.first);
		auto h2 = std::hash<T2>{}(p.second);
		return h1 ^ h2;
	}
};

int main() {
	//unordered_map<pair<int, int>, int> error_mmp;			// error
	unordered_map<pair<int, int>, int, pair_hash> ok_mmp;	// ok
}

  unordered_set 同理,都是用的哈希表

### C++ 中 `std::unordered_map` 的使用方法 #### 创建和初始化 `std::unordered_map` 可以创建一个空的 `std::unordered_map` 或者通过初始列表来填充它。 ```cpp #include <iostream> #include <unordered_map> int main() { // 创建一个空的 unordered_map std::unordered_map<int, std::string> map; // 插入键值对 map.insert({1, "one"}); map.emplace(2, "two"); // 使用初始列表创建并赋初值 std::unordered_map<int, std::string> initMap = {{3, "three"}, {4, "four"}}; } ``` #### 访问元素 可以通过下标操作符访问已存在的键对应的值;如果该键不存在,则会自动插入一个新的默认构造的值。 ```cpp // 假设已经有一个名为 myMapstd::unordered_map<int, double> double value = myMap[key]; // 如果 key 存在则返回对应值,否则插入新项并将 value 设为0.0[^1] ``` #### 迭代遍历 迭代器用于顺序访问容器内的所有元素。注意这里的顺序是没有定义过的,因为哈希表不保持任何特定顺序。 ```cpp for (auto& pair : map) { std::cout << "{" << pair.first << ": " << pair.second << "}\n"; } ``` #### 查找与删除 提供了成员函数如 `find()` 来定位指定键的位置以及 `erase()` 函数移除单个或多个条目。 ```cpp if (map.find(key) != map.end()) { // 键存在时的操作... } // 删除某个具体的键 map.erase(specificKey); // 清空整个映射 map.clear(); ``` #### 处理冲突 虽然内部实现细节通常由标准库处理,但在某些情况下可能需要考虑负载因子(load factor),即桶的数量相对于存储项目数的比例。当这个比例过高时可能会降低效率,因此有时有必要调整最大负载因子以优化性能。 ```cpp float currentLoadFactor = map.load_factor(); // 获取当前负载因子 size_t bucketCount = map.bucket_count(); // 获取桶数量 map.max_load_factor(0.75f); // 设置新的最大负载因子 map.rehash(bucketCount * 2); // 请求至少两倍于现有桶数的新桶数目 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值