繁体   English   中英

C++ 11 中无序集的无序映射

[英]Unordered map of unordered set in C++ 11

我想实现一些东西,将一组无序的整数映射到一个整数值。 Python dict 的某种 C++ 等价物,它具有集合作为键和整数作为值。

到目前为止,我使用了std::map<std::set<int>, int> set_lookup; 但据我了解,这太慢了,因为它使用了树木。 我不在乎顺序,只有速度很重要。

据我了解,所需的结构是std::unordered_map<std::unordered_set<int>, int, hash> set_lookup; 这需要一个哈希函数才能工作。

这是正确的方法吗? 最小运行示例会是什么样子? 我找不到哈希部分的样子。

不清楚您是询问定义散列函数的语法,还是询问如何为一组整数定义数学上良好的散列。

无论如何 - 如果是前者,以下是您应该如何在技术上为您的案例定义哈希函数:

template <>
struct hash<std::unordered_set<int>>
{
    std::size_t operator()(const std::unordered_set<int>& k) const
    {
        using std::size_t;
        using std::hash;
        using std::string;
    
        // ...
        // Here you should create and return a meaning full hash value:
        return 5;
    }
};
    
void main()
{
    std::unordered_map<std::unordered_set<int>, int> m;
}

写完之后,我加入了其他关于这是否是解决您的问题的好方向的评论。 你没有描述你的问题,所以我无法回答。

我理解 [ std::map<std::set<int>, int> set_lookup; ] 是不必要的慢,因为它使用树。

[ std::unordered_map<std::unordered_set<int>, int, hash> ] 是正确的方法吗?

这取决于。 如果您的密钥已创建然后未更改,并且您希望能够非常快速地进行大量查找,那么基于哈希表的方法确实会很好,但您需要两件事:

  • 能够散列键
  • 能够比较密钥

对于散列键,决定一个好的散列函数是一种艺术形式。 一个很少坏的 - 但有时比必要的慢 - 方法是使用 boost hash_combine (它足够短,您可以将其复制到您的代码中 - 请参阅此处的实现)。 但是,如果您的整数值在它们的大多数位上已经是非常随机的,那么只需将它们异或在一起就会产生一个很好的哈希值。 如果您不确定,请使用hash_combine或更好的哈希(例如 MURMUR32)。 散列所需的时间将取决于遍历的时间,并且遍历unordered_set通常涉及链表遍历(通常在内存页面中跳转并且对 CPU 缓存不友好)。 存储快速遍历值的最佳方法是在连续内存中 - 即std::vector<>std::array<>如果在编译时已知大小。

您需要做的另一件事是比较键是否相等:当键中的元素在内存中连续且一致排序时,这也是最快的。 同样,排序的std::vector<>std::array<>将是最好的。

也就是说,如果您的密钥集很大,并且您可以在密钥相等的统计保证上妥协,您可以使用例如 256 位哈希和代码,就好像哈希冲突总是对应于密钥相等一样。 这通常不是可接受的风险,但是如果您的哈希不易发生冲突并且您有例如 256 位哈希,则 CPU 可以运行平板聊天数千年哈希不同的键,并且即使一次也不太可能产生相同的哈希,所以它是我看到甚至金融公司在其核心内部数据库产品中使用的一种用途,因为它可以节省大量时间。

如果您受到这种妥协的诱惑,您会想要std::unordered_map<HashValue256, std::pair<int, std::vector<int>>> 要找到与一组整数关联的int ,您首先将它们散列,然后进行查找。 很容易编写一个哈希函数,它为set或排序的vector<>array<>产生相同的输出,因为您可以在遍历期间以相同的排序顺序将元素呈现给hash_combine之类的东西(即size_t seed = 0; for (auto& element : any_sorted_container) hash_combine(seed, element); )。 存储vector<int>意味着如果您想找到所有关键“集合”,您可以稍后遍历unordered_map - 如果您不需要这样做(例如,您只是通过已知的键查找int s当时的代码,并且您对良好哈希碰撞的统计不可能性感到满意,您甚至不需要存储键/向量): std::unordered_map<HashValue256, int>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM