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

本文深入探讨C++11中的unordered_map容器,解析其内部实现机制,特别是hashfunction的作用与自定义方法。通过实例展示如何处理自定义类型及解决编译错误,为读者提供全面的理解与实践指导。

  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 同理,都是用的哈希表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值