【问题标题】:Pass a parameter to an unordered_map (or set) hash struct将参数传递给 unordered_map(或集合)哈希结构
【发布时间】: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* 中,我将开始和目标位置作为数组,而不是节点。

标签: c++ unordered-map unordered-set hash-function


【解决方案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> m{initial_bucket_count, PosHash{4}};
    m[Pos{2, 3}] = 23;
    m[Pos{1, 1}] = 11;
    m[Pos{3, 1}] = 11;
    m[Pos{3, 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 的回答有初始化地图的正确方法,略有不同,还是谢谢!
猜你喜欢
  • 2020-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2013-09-04
  • 2023-03-24
  • 2018-04-11
  • 1970-01-01
  • 2013-09-27
相关资源
最近更新 更多