仅使用带有键的 unordered_map 来存储指针(忽略值)

Posted

技术标签:

【中文标题】仅使用带有键的 unordered_map 来存储指针(忽略值)【英文标题】:Using unordered_map with key only to store pointers (dismiss value) 【发布时间】:2021-12-04 03:41:50 【问题描述】:

我正在实现一种算法,用于检查网格中的节点是否具有特定值。为了存储我已经检查过的节点的信息,我想使用一个 unordered_map 和指向该节点的指针作为键。然后我可以简单地使用 umap.find(pointer) 来查看节点是否已被检查并跳过它。这样我可以在 O(n) 时间内完成。

但是,我不需要实际存储地图的值。密钥本身就是足够的信息。那么 std::unordered_map 甚至是正确的解决方案吗?如果是这样,我应该为“价值”字段最大化性能吗?我有一个 32 位的嵌入式系统,所以我想把 uint32_t 或 uint_fast32_t 放在那里。

tl;博士:

std::unordered_map 是存储没有值的键的正确工具吗? 本机散列函数是否适用于指针?或者您会建议不同的哈希算法吗? 如果使用 std::unordered_map 来优化性能,我应该将什么作为地图的“价值”?

【问题讨论】:

【参考方案1】:

std::unordered_map 是存储没有值的键的正确工具吗?

在这些情况下我会使用std::unordered_set

本机哈希函数是否适用于指针?

是的。它很可能只是从指向std::size_t 的指针的转换。

如果使用 std::unordered_map 来优化性能,我应该将什么作为地图的“价值”?

如果您改用std::unordered_set,则没有值,只有指针。

【讨论】:

【参考方案2】:

std::unordered_map 是存储没有值的键的正确工具吗?

否 - std::unordered_set 是当您没有不同的键和值时使用的。

本机散列函数是否适用于指针?或者您会建议不同的哈希算法吗?

编译器提供的“本机”哈希函数可能会将指针值转换为size_t - 一种身份哈希。根据您的标准库选择的折衷方案,这可能会或可能不会很好地工作。 GCC 和 clang 在哈希表中使用质数的桶,所以它可以正常工作。 Visual C++(和许多非标准哈希表实现)使用 2 的幂(即 128、256、512...)。使用 2 的幂是因为将它们映射到存储桶非常快 - 只需 AND 与按位掩码 (127、255、511) 即可保留您需要的许多不太重要的位。使用指针这样做的问题是,通常指向的对象有一些对齐,所以它们可能都是例如的倍数。 4 或 8。 8 的倍数始终将三个最低有效位设置为 0:这些位不会有助于将值随机放置在存储桶中。相反,只有每 8 个存储桶将接收到被散列的元素的任何份额。如果您有这样的实现,那么您最好使用更好的哈希函数。至少,您可以说将指针值右移足以移除已知的零。

如果使用 std::unordered_map 来优化性能,我应该将什么作为地图的“价值”?

同样,您应该使用std::unordered_set,因此不必担心值。

【讨论】:

谢谢你很有见地。我正在使用 gcc 并且正在开发非常特定于平台的代码,所以没关系。但是您的帖子表明在任何情况下将位向右移动 3 位可能是一种好习惯? @glades:如果您使用 gcc,则没有必要也不值得费心创建自定义哈希函数。如果您正在使用具有 2 次幂存储桶计数的哈希表实现,那么对于指向 8 字节对齐对象的指针(例如,大多数包含一个或多个指针的结构,int64_t、uint64_t , 或双打将 8 字节对齐)。其他结构(例如,只有 32 位整数)可能是 4 字节对齐的(因此移位 2),甚至是未对齐的(字符数据通常不需要对齐)(所以不要移位)。

以上是关于仅使用带有键的 unordered_map 来存储指针(忽略值)的主要内容,如果未能解决你的问题,请参考以下文章

修改 boost unordered_map 中键的值

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

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

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

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

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