c ++ - unordered_map复杂性

时间:2013-03-18 06:34:28

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

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

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

我关心的是,如果无序地图中没有关键字,那么复杂性就会变得很复杂。例如,如果我使用unordered_map :: find():来确定我的哈希表中是否存在键,那么它将如何给我一个答案呢?它是否实际迭代了所有键?

我非常感谢帮助。

3 个答案:

答案 0 :(得分:6)

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

为了确保存储桶中的元素数量很少,您就可以了 必须确保散列函数有效。什么 有效的手段取决于被散列的类型和价值。 (MS实现使用FNV,这是最好的之一 通用哈希周围,但如果你有特殊的知识 您将看到的实际数据,您可能会做得更好。) 另一件可以帮助减少每个元素数量的事情 铲斗是为了强制更多的铲斗或使用更小的载荷系数。 对于第一个,您可以传递最小初始数 bucket作为构造函数的参数。如果你知道的话 您可以在地图中使用的元素总数 以这种方式控制负载系数。你也可以误认为最低限度 表格填写后,通过调用的桶数 rehash。否则,有一个功能 您可以使用std::unordered_map<>::max_load_factor。它 不保证做任何事情,但在任何合理的情况下 实施,它会。请注意,如果您已在已使用它 填写unordered_map,您可能需要打电话 unordered_map<>::rehash之后。

(关于标准,有几点我不明白 unordered_map:为什么加载因子是float,而不是。{ double;为什么不要求有效果;为什么呢 不会自动为您调用rehash。)

答案 1 :(得分:3)

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

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

所以,作为对你的问题的一个冗长的回答,只要哈希函数是合理的,你将得到O(1)查找,它必须迭代(平均){{1} }键给你一个“否定”的结果。

答案 2 :(得分:1)

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

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

  

<强>复杂性   平均情况:不变。   最坏情况:容器尺寸呈线性。

     

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

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

我认为unordered_map::count功能的文档内容更丰富:

  

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