将参数传递给 unordered_map(或集合)哈希结构

Posted

技术标签:

【中文标题】将参数传递给 unordered_map(或集合)哈希结构【英文标题】:Pass a parameter to an unordered_map (or set) hash struct 【发布时间】:2020-08-24 16:35:10 【问题描述】:

我有以下结构:

array<int, 2> map_size;

struct Node
    int id;
    array<int, 2> pos;
    vector<Node*> nbs;
    bool in_open;
    bool in_closed;
;

每个节点都有一个在 map_size(全局变量)范围内的位置 (pos)。

我正在使用以下无序地图

struct PosHash
    public:
    size_t operator()(array<int, 2> const& pos) const
        return pos[1] + pos[0]*map_size[1];
    
;

struct PosCompare
    bool operator()(const array<int, 2>& pos1, const array<int, 2>& pos2) const
        if (pos1[0] == pos2[0] and pos1[1] == pos2[1])
            return true;
        
        else
            return false;
        
    
;

unordered_map<array<int, 2>, Node*, PosHash, PosCompare> nodes;

map_size 是散列函数中使用的全局变量,可以让我得到一个完美的散列。 但是,我想将 map_size 作为参数传递给 PosHash,这样可以避免使用全局变量。我该怎么做?

PD:map_size 值在执行时间确定

【问题讨论】:

PosHash 拥有一个map_size 数据成员怎么样。让它的构造函数初始化它。然后将此对象传递给unordered_map的构造函数(在适当的位置) map_size 是您的地图的关键。 pos[]Node 中的变量,而这又是unordered_map 中的映射值。散列函数PosHash应该接收键值并产生Nodes,即pos[]。为什么哈希函数需要映射值来产生映射值? @User10482 我认为就是这样。但是不知道怎么在unordered_map这一行传参数(map_size是在执行时决定的) @Lingo 这是针对 A* 的。在 A* 中,我将开始和目标位置作为数组,而不是节点。 【参考方案1】:

这是一个完整的程序,展示了如何构造一个存储特定值的PosHash 对象。请注意,您不需要自定义比较 - std::arrays 无论如何都会以相同的方式进行比较。

#include <iostream>
#include <array>
#include <unordered_map>

using Pos = std::array<int, 2>;

struct PosHash 
    PosHash(int m) : m_m  
    size_t operator()(const Pos& pos) const 
        return pos[1] + pos[0] * m_;
    
    int m_;
;

int main()

    static constexpr size_t initial_bucket_count = 5;
    // for illustrative purposes, will just map to ints
    std::unordered_map<Pos, int, PosHash> minitial_bucket_count, PosHash4;
    m[Pos2, 3] = 23;
    m[Pos1, 1] = 11;
    m[Pos3, 1] = 11;
    m[Pos3, 2] = 32;
    for (const auto& x : m)
        std::cout << x.first[0] << ',' << x.first[1] << '=' << x.second << '\n';

更一般地说,这是一个“弱”哈希函数。它可能是“完美”地产生足够分散的散列值以避免散列值空间中的冲突,但这并不意味着如果你将该空间折叠到较少数量的桶中,你就不会发生冲突。

【讨论】:

谢谢!这正是我所需要的。我不知道如何将地图大小传递给 unordered_map。无论如何,我知道这个哈希函数是完美的,因为具有相同位置的节点总是相同的节点。这个哈希函数返回地图的一维数组中的位置。 现在我知道问题出在桶的数量上,如果桶的数量有限,最好使用像 djb2 这样的标准字符串哈希函数 @BMarin:哦,很好-我想知道是否应该尝试进一步解释。为多部分键组合散列的合理通用方法是 hash_combine - 你基本上会说 size_t seed = 0; hash_combine(seed, pos[0]); hash_combine(seed, pos[1]); 然后使用 seed 作为你的散列值。【参考方案2】:

您可以将map_size 作为PosHash 结构中的数据成员。

struct PosHash
    public:
    size_t operator()(array<int, 2> const& pos) const
        return pos[1] + pos[0]*map_size[1];
    

    // Contructor that initializes the data member
    PosHash(std::intializer_list<int> map_dim) : map_size(map_dim) 
      // Other stuff
    ;
    
    std::array<int, 2> map_size; // data member of the struct
;

然后,您可以使用所需的 map_size 数组构造一个 PosHash 对象。将此对象传递给您的unordered_map

PosHash myPosHash(1, 2);

std::unordered_map<array<int, 2>, Node*, PosHash, PosCompare> nodes(\\intial args\\, myPosHash);

查看std::unordered_map here 的不同可用构造函数。您需要在 hasher 参数之前显式指定所有参数。这些将取决于您的需求。 我能想到的最简单的是

nodes(0, myPosHash);  //initial #buckets, hasher object

【讨论】:

我该如何初始化 unordered_map? @BMarin 添加。您可以按照自己的方式获得PosHash 的构造函数和其他详细信息。希望这会有所帮助。 Tony Delroy 的回答有初始化地图的正确方法,略有不同,还是谢谢!

以上是关于将参数传递给 unordered_map(或集合)哈希结构的主要内容,如果未能解决你的问题,请参考以下文章

将 Laravel 集合中的 id 参数传递给 Vue 组件

如何将无限参数和一个或两个参数传递给 JavaScript 函数? [复制]

Omnipay - 如何将“自定义”或“发票”参数传递给 Paypal?

从 android 或 iOS 将参数传递给颤振模块

将多个参数传递给 GraphQL 查询

如何将 C# 对象作为参数传递给 Javascript 函数