【问题标题】:Selection of map or unordered_map based on keys's type根据键的类型选择 map 或 unordered_map
【发布时间】:2012-11-10 16:17:15
【问题描述】:
一个常见的问题是我们是否应该使用 unordered_map 或 map 来加快访问速度。
这个问题最常见(相当古老)的答案是:
如果您想直接访问单个元素,请使用 unordered_map,但如果您想遍历元素(很可能以排序方式),请使用 map。
我们在做这样的选择时不应该考虑键的数据类型吗?
因为一种数据类型(比如 int)的哈希算法可能比其他(比如字符串)更容易发生冲突。
如果是这种情况(哈希算法很容易发生冲突),那么我可能会使用 map 即使是直接访问,因为在这种情况下 O(1) 恒定时间(可能是在大量输入上的平均值) unordered_map 映射大于 lg(N),即使 N 值相当大。
【问题讨论】:
标签:
c++
algorithm
boost
data-structures
c++11
【解决方案1】:
你提出了一个很好的观点......但你关注的是错误的部分。
问题本身不在于密钥的类型,而在于用于为该密钥派生哈希值的哈希函数。
字典顺序简单:如果你告诉我你想根据它的 3 个字段对结构进行排序(并且它们已经支持自己排序),那么我会写:
bool operator<(Struct const& left, Struct const& right) {
return boost::tie(left._1, left._2, left._3)
< boost::tie(right._1, right._2, right._3);
}
我已经完成了!
但是写一个散列函数是困难。你需要一些关于你的数据分布(统计)的知识,你可能需要防止特制的攻击等等......老实说,我不希望很多人能够制作一个好的散列函数。但最糟糕的是,作曲也很困难!给定两个独立的字段,组合它们的哈希值 right 很难(提示:boost::hash_combine)。
因此,确实,如果您不知道自己在做什么并且正在处理用户制作的数据,请坚持使用map。它可能更慢(不确定),但更安全。
【解决方案2】:
实际上并没有像容易发生碰撞的对象这样的东西,因为这个东西取决于您使用的散列函数。假设对象不相同 - 有一些功能可用于创建要使用的信息散列函数。
假设您对自己的数据有一定了解 - 并且您知道某些散列函数 h1() 可能会发生很多冲突 - 那么您应该找到并使用更适合的不同散列函数 h2()这个任务。
也就是说,还有其他问题以及为什么偏爱基于树的数据结构而不是哈希基(例如延迟和集合的大小),my answer in this thread 涵盖了一些问题。
【解决方案3】:
在这件事上试图太聪明是没有意义的。与往常一样,分析、比较、优化(如果有用)。涉及的因素很多——其中相当多的因素没有在标准中指定,并且会因编译器而异。有些事情在特定硬件上可能会更好或更差。如果您对这些东西感兴趣(或付费假装感兴趣),您应该更系统地了解这些东西。您可以先了解一些实际的散列函数及其特征。很难找到一个哈希函数——对于所有实际目的——不比随机但可重复的值更容易发生冲突——只是有时接近那个点比处理一些额外的冲突要慢。