【问题标题】:c++ - unordered_map complexityc++ - unordered_map 复杂度
【发布时间】:2013-03-06 10:37:23
【问题描述】:

我需要创建一个查找函数,其中 (X,Y) 对对应于特定的 Z 值。对此的一个主要要求是我需要尽可能接近 O(1) 复杂度。我的计划是使用 unordered_map。

我通常不使用哈希表进行查找,因为查找时间对我来说从来都不重要。我是否正确地认为只要我构建了没有冲突的 unordered_map,我的查找时间就是 O(1)?

然后我担心的是,如果无序映射中不存在密钥,那么复杂性会变成什么。例如,如果我使用 unordered_map::find(): 来确定我的哈希表中是否存在某个键,它将如何给我一个答案?它实际上会遍历所有键吗?

非常感谢您的帮助。

【问题讨论】:

    标签: c++ hashtable complexity-theory unordered-map


    【解决方案1】:

    与任何哈希表一样,最坏的情况总是线性复杂度(编辑:如果您构建的地图没有任何冲突,就像您在原始帖子中所说的那样,那么您将永远不会看到这种情况) :

    http://www.cplusplus.com/reference/unordered_map/unordered_map/find/

    复杂性 平均情况:恒定。 最坏的情况:容器大小呈线性关系。

    返回值 如果找到指定的键值,则为元素的迭代器;如果在容器中未找到指定的键,则为 unordered_map::end。

    但是,由于 unordered_map 只能包含唯一键,您将看到恒定时间的平均复杂度(容器首先检查哈希索引,然后迭代该索引处的值)。

    我认为unordered_map::count 函数的文档信息更丰富:

    在容器中搜索 key 为 k 的元素并返回 找到的元素数量。因为 unordered_map 容器没有 允许重复键,这意味着该函数实际上 如果容器中存在具有该键的元素,则返回 1,并且 否则为零。

    【讨论】:

    • 我现在对 jakar 在这里的回答感到困惑:stackoverflow.com/questions/4395050/… 我会将此评论解释为可以完成。不是这样吗?
    • @user1764386: 好吧,如果 find 不能将迭代器返回给你的值,它必须返回 something,所以 unordered_map::end 是最好的选择。跨度>
    • 感谢您的帮助。我的意思是我对他的回答有些困惑,因为我将其解释为如果密钥不在 unordered_map 中,复杂性将优于 O(N)。
    • @user1764386 平均而言是这样。如果您看到所有输入散列到相同值的不太可能的最坏情况,则数据结构必须遍历整个列表。
    • 您介意更详细地解释一下吗?我可以避免将任何两个键映射到相同的值吗?我正在根据输入数据一次构建 unordered_map。我以后再也不会添加它了。
    【解决方案2】:

    在散列数据结构中没有冲突是非常困难的(如果不是不可能的给定散列函数和任何类型的数据)。它还需要一个与键数完全相等的表大小。不,它不需要那么严格。只要哈希函数以相对统一的方式分配值,就会有O(1) 查找复杂度。

    哈希表通常只是带有处理冲突的链表的数组(这是链接方法 - 还有其他方法,但这可能是处理冲突最常用的方法)。因此,要查找一个值是否包含在存储桶中,它必须(可能)迭代该存储桶中的所有值。因此,如果哈希函数为您提供均匀分布,并且有 N 个桶,并且总共有 M 个值,那么每个桶应该(平均)有 M/N 个值。只要该值不太大,就允许O(1) 查找。

    因此,作为对您的问题的一个冗长的回答,只要散列函数是合理的,您将获得 O(1) 查找,它必须迭代(平均)O(M/N) 键以给出你是一个“否定”的结果。

    【讨论】:

      【解决方案3】:

      标准或多或少需要使用桶进行碰撞 分辨率,这意味着实际查找时间将 可能与元素数量成线性关系 桶,无论元素是否存在。 有可能使它成为 O(lg N),但通常不会这样做, 因为桶中的元素数量应该很少, 如果哈希表使用正确。

      为确保桶中的元素数量较少,您 必须确保散列函数有效。什么 有效的方法取决于被散列的类型和值。 (MS 实现使用 FNV,这是最好的之一 通用哈希,但如果你有特殊的知识 您将看到的实际数据,您可能会做得更好。) 另一件事可以帮助减少每个元素的数量 bucket是强制更多的bucket或使用更小的负载因子。 首先,您可以通过最小初始数量 buckets 作为构造函数的参数。如果你知道 将在地图中的元素总数,您可以 以这种方式控制负载系数。您也可以设置一个最小值 表被填满后的桶数,通过调用 rehash。否则,有一个功能 std::unordered_map<>::max_load_factor 您可以使用。它 不保证做任何事情,但在任何合理的 执行,它会。请注意,如果您已经在 填写unordered_map,您可能需要致电 之后unordered_map<>::rehash

      (关于标准有几件事我不明白 unordered_map:为什么负载因子是float,而不是 double;为什么不需要产生效果;以及为什么 不会自动为您调用rehash。)

      【讨论】:

        猜你喜欢
        • 2013-11-05
        • 1970-01-01
        • 2014-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-27
        相关资源
        最近更新 更多