在c++11 的unordered_set和unordered_map中插入pair或tuple作为键值

参考:https://blog.csdn.net/pineappleKID/article/details/108341064

想完成的任务 与 遇到的问题
想在c++11 的unordered_set和unordered_map中插入pair或tuple作为键值

std::unordered_map<std::pair<std::string,std::string>, int> m;

会报错
/usr/include/c++/4.9/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<std::tuple<int, int>, std::hash<std::tuple<int, int> > >’
或者
/usr/include/c++/4.9/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<std::pair<std::basic_string, std::basic_string >, std::hash<std::pair<std::basic_string, std::basic_string > > >’
C++的std::pair是无法std::hash的,为了在unordered_set和unordered_map中使用std::pair,有如下方法。还有个前提,pair 和 tuple 中的元素本身得是可以 std::hash 哈希的。

方法一:专门写个可用于std::pair的std::hash

#include <iostream>
#include <unordered_map>
#include <utility>

typedef std::pair<std::string,std::string> pair;

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

int main()
{
	std::unordered_map<pair,int,pair_hash> unordered_map =
	{
		{{"C++", "C++11"}, 2011},
		{{"C++", "C++14"}, 2014},
		{{"C++", "C++17"}, 2017},
		{{"Java", "Java 7"}, 2011},
		{{"Java", "Java 8"}, 2014},
		{{"Java", "Java 9"}, 2017}
	};

	for (auto const &entry: unordered_map)
	{
		auto key_pair = entry.first;
		std::cout << "{" << key_pair.first << "," << key_pair.second << "}, "
				  << entry.second << '\n';
	}

	return 0;
}

输出

{Java,Java 8}, 2014
{Java,Java 7}, 2011
{Java,Java 9}, 2017
{C++,C++17}, 2017
{C++,C++14}, 2014
{C++,C++11}, 2011

注意:上面的代码使用的异或(XOR),由于x^x == 0并且x^y == y^x,所以应该配合一些位运算的shift或rotate来做。

方法二:使用boost::hash
boost::hash可以用于哈希integers, floats, pointers, strings, arrays, pairs 以及其它 STL 里的东西

#include <iostream>
#include <boost/functional/hash.hpp>
#include <unordered_map>
#include <utility>

typedef std::pair<std::string,std::string> pair;

int main()
{
	std::unordered_map<pair,int,boost::hash<pair>> unordered_map =
	{
		{{"C++", "C++11"}, 2011},
		{{"C++", "C++14"}, 2014},
		{{"C++", "C++17"}, 2017},
		{{"Java", "Java 7"}, 2011},
		{{"Java", "Java 8"}, 2014},
		{{"Java", "Java 9"}, 2017}
	};

	for (auto const &entry: unordered_map)
	{
		auto key_pair = entry.first;
		std::cout << "{" << key_pair.first << "," << key_pair.second << "}, "
				  << entry.second << '\n';
	}

	return 0;
}

输出

{Java,Java 8}, 2014
{Java,Java 9}, 2017
{Java,Java 7}, 2011
{C++,C++17}, 2017
{C++,C++14}, 2014
{C++,C++11}, 2011

注意:boost的hash的位置改过,有网友说boost 1.72的hash在

#include <boost/container_hash/extensions.hpp>

原话是

By the way the functional hash has moved. I am not sure when, but in boost 1.72 it is in #include <boost/container_hash/extensions.hpp> I am not sure why the boost hash function for a tuple is not documented somewhere.

方法三:hash_combine
把下列代码放在任何你想实现本文目的代码头文件里
原话是

This works on gcc 4.5 allowing all c++0x tuples containing standard hashable types to be members of unordered_map and unordered_set without further ado. (I put the code in a header file and just include it.)
The function has to live in the std namespace so that it is picked up by argument-dependent name lookup (ADL).

#include <tuple>
namespace std{
    namespace
    {

        // Code from boost
        // Reciprocal of the golden ratio helps spread entropy
        //     and handles duplicates.
        // See Mike Seymour in magic-numbers-in-boosthash-combine:
        //     http://stackoverflow.com/questions/4948780

        template <class T>
        inline void hash_combine(std::size_t& seed, T const& v)
        {
            seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }

        // Recursive template code derived from Matthieu M.
        template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
        struct HashValueImpl
        {
          static void apply(size_t& seed, Tuple const& tuple)
          {
            HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
            hash_combine(seed, std::get<Index>(tuple));
          }
        };

        template <class Tuple>
        struct HashValueImpl<Tuple,0>
        {
          static void apply(size_t& seed, Tuple const& tuple)
          {
            hash_combine(seed, std::get<0>(tuple));
          }
        };
    }

    template <typename ... TT>
    struct hash<std::tuple<TT...>> 
    {
        size_t
        operator()(std::tuple<TT...> const& tt) const
        {                                              
            size_t seed = 0;                             
            HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
            return seed;                                 
        }                                              

    };
}

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
unordered_set和unordered_mapC++11新增加的两个关联式容器,它们的区别主要体现在以下几个方面: 1. 底层实现:unordered_set和unordered_map的底层都是哈希表,而setmap的底层是红黑树。哈希表是一种根据键值直接进行访问的数据结构,而红黑树是一种自平衡的二叉搜索树。 2. 排序:unordered_set是不可排序的,而set是有序的。unordered_map是无序的,而map是有序的。这是因为哈希表是根据键值的哈希值进行存储和访问的,没有固定的顺序。 3. 迭代器:unordered_set和unordered_map使用的是单向迭代器,而setmap使用的是双向迭代器。单向迭代器只能从前往后遍历容器的元素,而双向迭代器可以从前往后和从后往前遍历。 4. 效率:由于底层实现的不同,unordered_set和unordered_map插入、查找和删除操作的时间复杂度都是O(1),而setmap的时间复杂度是O(logN)。因此,unordered_set和unordered_map相对于setmap来说,在大部分情况下具有更高的效率。 综上所述,unordered_set和unordered_mapsetmap在底层实现、排序、迭代器和效率上存在一些区别。选择使用哪个容器取决于具体的需求和性能要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++ 哈希表及unordered_set + unordered_map容器](https://blog.csdn.net/qq_60750110/article/details/126746419)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [算法(42)-数组等值切割-前缀累加和-哈希表Map-set版-C++](https://download.csdn.net/download/weixin_38710566/14039060)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值