【问题标题】:boost::unordered_map is... ordered?boost::unordered_map 是...有序的?
【发布时间】:2010-06-14 18:28:39
【问题描述】:

我有一个 boost::unordered_map,但它似乎是有序的,给我一种“你做错了”的压倒性感觉。为什么输出到这个顺序?我本来希望底层的散列算法随机化这个顺序:

#include <iostream>
#include <boost/unordered_map.hpp>

int main()
{
    boost::unordered_map<int, int> im;

    for(int i = 0; i < 50; ++i)
    {
        im.insert(std::make_pair(i, i));
    }

    boost::unordered_map<int, int>::const_iterator i;

    for(i = im.begin(); i != im.end(); ++i)
    {
        std::cout << i->first << ", " << i->second << std::endl;
    }

    return 0;
}

...给我...

0, 0
1, 1
2, 2
...
47, 47
48, 48
49, 49

在检查boost的源代码时:

inline std::size_t hash_value(int v)
{
    return static_cast<std::size_t>(v);
}

...这将解释它。下面的答案也包含更高层次的思考,我发现这很有用。

【问题讨论】:

  • 不要插入i,而是尝试插入(并在插入的同时打印到控制台)随机数,看看结果是否仍然是有序的,或者它们是否只是按它们的顺序排序被插入...
  • 如果你需要随机顺序,使用 std::random_shuffle :)
  • @Drakosha:我不是在寻找随机顺序,但有序的 unordered_map 让我感到不安。 (非最小测试用例有几千个整数,但它们仍然有序)
  • @FWFD: (哈哈)插入 rand() 给我一个无序的输出。
  • @Thanatos:和我想的一样! :)

标签: c++ boost


【解决方案1】:

虽然由于我不是 C++ 人员,所以我无法与 boost 内部人员交谈,但我可以提出一些更高级的问题来缓解您的担忧:

1) “无序”地图的保证是什么?假设您有一个有序的地图,并且您想要创建一个不保证有序的地图。初始实现可以简单地使用有序映射。提供比您宣传的更强保证几乎从来都不是问题。

2) 散列函数是散列 X -> int 的东西。如果你已经有一个整数,你可以使用恒等函数。虽然它可能不是在所有情况下都是最有效的,但它可以解释您所看到的行为。

基本上,看到这样的行为并不一定是个问题。

【讨论】:

  • 我没想到哈希函数会使用恒等函数,但这似乎正是 boost 正在做的事情。我想如果没有输入的领域知识,这样的散列将与任何散列一样起作用。
  • @Thanatos - 因为散列函数的结果是size_t(至少对于boost::unordered_map)并且int 总是适合size_t,所以没有理由这样做除了身份函数之外的任何东西来散列int
  • @Michael Burr - 我并不关心语言的语义 - 我正在研究哈希函数的目的是防止输入之间的冲突,以便哈希表有机会为 O(1)。我习惯于看到相当随机的哈希函数输出。
  • @Thantos:但是如果要散列的属性的大小小于或等于散列,那么没有理由对属性执行任何转换以产生完美的散列 - 无论语言如何。在这些情况下,identify 函数会产生一个漂亮、简单的完美哈希。
【解决方案2】:

这可能是因为您的哈希是小整数。 哈希表通常会像这样计算放置项目的桶数:bucket_index = hash%p 其中p 是质数,这是哈希表桶的数量,它大到足以提供低冲突频率。

对于整数哈希等于整数的值。 你有很多数据,所以 hashtable 选择了一个大的 p。 对于任何大于 i 的 p,bucket_index = i%p = i

在迭代时,哈希表会按照索引的顺序从其存储桶中返回项目,对您而言,这就是键的顺序。 :)

如果您想看到一些随机性,请尝试使用更大的数字。

【讨论】:

    【解决方案3】:

    你做得对。 unordered_map 不声称具有随机顺序。事实上,它对秩序没有任何要求。你不应该期待任何东西的顺序,那会导致混乱!

    【讨论】:

      【解决方案4】:

      这是因为默认情况下映射按“键的插入顺序”排序,这意味着如果您插入键 1,2,3,4,5 并打印它,您将始终得到 1,2,3,4,5 所以它看起来有序。尝试添加随机键值并查看结果。它不会每次都一样,因为它不应该是。

      【讨论】:

        猜你喜欢
        • 2011-05-16
        • 2010-12-09
        • 2012-05-23
        • 1970-01-01
        • 1970-01-01
        • 2016-01-24
        • 2010-11-06
        • 2014-10-10
        • 2011-04-28
        相关资源
        最近更新 更多