gpt4 book ai didi

使用自定义类类型作为键的 C++ unordered_map

转载 作者:行者123 更新时间:2023-12-02 10:39:15 30 4
gpt4 key购买 nike

我正在尝试使用自定义类作为 unordered_map 的键,如下所示:

#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

class node;
class Solution;

class Node {
public:
int a;
int b;
int c;
Node(){}
Node(vector<int> v) {
sort(v.begin(), v.end());
a = v[0];
b = v[1];
c = v[2];
}

bool operator==(Node i) {
if ( i.a==this->a && i.b==this->b &&i.c==this->c ) {
return true;
} else {
return false;
}
}
};

int main() {
unordered_map<Node, int> m;

vector<int> v;
v.push_back(3);
v.push_back(8);
v.push_back(9);
Node n(v);

m[n] = 0;

return 0;
}

但是,g++ 给了我以下错误:
In file included from /usr/include/c++/4.6/string:50:0,
from /usr/include/c++/4.6/bits/locale_classes.h:42,
from /usr/include/c++/4.6/bits/ios_base.h:43,
from /usr/include/c++/4.6/ios:43,
from /usr/include/c++/4.6/ostream:40,
from /usr/include/c++/4.6/iostream:40,
from 3sum.cpp:4:
/usr/include/c++/4.6/bits/stl_function.h: In member function ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Node]’:
/usr/include/c++/4.6/bits/hashtable_policy.h:768:48: instantiated from ‘bool std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_M_compare(const _Key&, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_Hash_code_type, std::__detail::_Hash_node<_Value, false>*) const [with _Key = Node, _Value = std::pair<const Node, int>, _ExtractKey = std::_Select1st<std::pair<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_Hash_code_type = long unsigned int]’
/usr/include/c++/4.6/bits/hashtable.h:897:2: instantiated from ‘std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node* std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_M_find_node(std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node*, const key_type&, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type) const [with _Key = Node, _Value = std::pair<const Node, int>, _Allocator = std::allocator<std::pair<const Node, int> >, _ExtractKey = std::_Select1st<std::pair<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, _Hash = std::__detail::_Default_ranged_hash, _RehashPolicy = std::__detail::_Prime_rehash_policy, bool __cache_hash_code = false, bool __constant_iterators = false, bool __unique_keys = true, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node = std::__detail::_Hash_node<std::pair<const Node, int>, false>, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::key_type = Node, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type = long unsigned int]’
/usr/include/c++/4.6/bits/hashtable_policy.h:546:53: instantiated from ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](const _Key&) [with _Key = Node, _Pair = std::pair<const Node, int>, _Hashtable = std::_Hashtable<Node, std::pair<const Node, int>, std::allocator<std::pair<const Node, int> >, std::_Select1st<std::pair<const Node, int> >, std::equal_to<Node>, std::hash<Node>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’
3sum.cpp:149:5: instantiated from here
/usr/include/c++/4.6/bits/stl_function.h:209:23: error: passing ‘const Node’ as ‘this’ argument of ‘bool Node::operator==(Node)’ discards qualifiers [-fpermissive]
make: *** [threeSum] Error 1

我想,我需要告诉 C++ 如何散列类 Node ,但是,我不太确定该怎么做。我怎样才能完成这项任务?

最佳答案

为了能够使用std::unordered_map (或其他无序关联容器之一)具有用户定义的键类型,您需要定义两件事:

  • 一个 哈希函数 ;这必须是一个覆盖 operator() 的类并计算给定键类型对象的哈希值。一种特别直接的方法是专门化 std::hash您的 key 类型的模板。
  • 一个 相等比较函数 ;这是必需的,因为散列不能依赖于散列函数总是为每个不同的键提供唯一的散列值这一事实(即,它需要能够处理冲突),因此它需要一种比较两个给定键的方法精确匹配。您可以将其实现为覆盖 operator() 的类。 ,或作为 std::equal 的特化,或者——最简单的——通过重载operator==()对于您的 key 类型(就像您已经做过的那样)。

  • 散列函数的困难在于,如果您的键类型由多个成员组成,您通常会让散列函数计算各个成员的散列值,然后以某种方式将它们组合成整个对象的散列值。为了获得良好的性能(即很少发生冲突),您应该仔细考虑如何组合各个散列值,以确保您避免为不同的对象过于频繁地获得相同的输出。

    散列函数的一个相当好的起点是使用位移和按位异或来组合各个散列值。例如,假设这样的键类型:
    struct Key
    {
    std::string first;
    std::string second;
    int third;

    bool operator==(const Key &other) const
    { return (first == other.first
    && second == other.second
    && third == other.third);
    }
    };

    这是一个简单的散列函数(改编自 cppreference example for user-defined hash functions 中使用的散列函数):
    namespace std {

    template <>
    struct hash<Key>
    {
    std::size_t operator()(const Key& k) const
    {
    using std::size_t;
    using std::hash;
    using std::string;

    // Compute individual hash values for first,
    // second and third and combine them using XOR
    // and bit shifting:

    return ((hash<string>()(k.first)
    ^ (hash<string>()(k.second) << 1)) >> 1)
    ^ (hash<int>()(k.third) << 1);
    }
    };

    }

    有了这个,你可以实例化一个 std::unordered_map对于键类型:
    int main()
    {
    std::unordered_map<Key,std::string> m6 = {
    { {"John", "Doe", 12}, "example"},
    { {"Mary", "Sue", 21}, "another"}
    };
    }

    它将自动使用 std::hash<Key>如上为哈希值计算定义的, operator==定义为 Key 的成员函数用于平等检查。

    如果您不想在 std 中专门化模板命名空间(尽管在这种情况下它是完全合法的),您可以将哈希函数定义为一个单独的类并将其添加到映射的模板参数列表中:
    struct KeyHasher
    {
    std::size_t operator()(const Key& k) const
    {
    using std::size_t;
    using std::hash;
    using std::string;

    return ((hash<string>()(k.first)
    ^ (hash<string>()(k.second) << 1)) >> 1)
    ^ (hash<int>()(k.third) << 1);
    }
    };

    int main()
    {
    std::unordered_map<Key,std::string,KeyHasher> m6 = {
    { {"John", "Doe", 12}, "example"},
    { {"Mary", "Sue", 21}, "another"}
    };
    }

    如何定义更好的哈希函数?如上所述,定义一个好的散列函数对于避免冲突和获得良好的性能很重要。对于一个真正好的结果,您需要考虑所有字段的可能值的分布,并定义一个散列函数,将该分布投影到尽可能广泛且均匀分布的可能结果空间。

    这可能很困难;上面的 XOR/位移位方法可能不是一个糟糕的开始。为了更好的开始,您可以使用 hash_valuehash_combine Boost 库中的函数模板。前者的作用与 std::hash 类似。对于标准类型(最近还包括元组和其他有用的标准类型);后者可帮助您将各个散列值合并为一个。这是使用 Boost 辅助函数的哈希函数的重写:
    #include <boost/functional/hash.hpp>

    struct KeyHasher
    {
    std::size_t operator()(const Key& k) const
    {
    using boost::hash_value;
    using boost::hash_combine;

    // Start with a hash value of 0 .
    std::size_t seed = 0;

    // Modify 'seed' by XORing and bit-shifting in
    // one member of 'Key' after the other:
    hash_combine(seed,hash_value(k.first));
    hash_combine(seed,hash_value(k.second));
    hash_combine(seed,hash_value(k.third));

    // Return the result.
    return seed;
    }
    };

    这是一个不使用 boost 的重写,但使用了组合哈希的好方法:
    namespace std
    {
    template <>
    struct hash<Key>
    {
    size_t operator()( const Key& k ) const
    {
    // Compute individual hash values for first, second and third
    // http://stackoverflow.com/a/1646913/126995
    size_t res = 17;
    res = res * 31 + hash<string>()( k.first );
    res = res * 31 + hash<string>()( k.second );
    res = res * 31 + hash<int>()( k.third );
    return res;
    }
    };
    }

    关于使用自定义类类型作为键的 C++ unordered_map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52601966/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com