我在stackoverflow上已经阅读了很多关于unordered_map (c ++ 11) 时间复杂度的内容,但我还没有找到答案对于我的问题。
让我们假设按整数索引(例如):
插入/在函数处不断工作(平均时间),因此这个例子需要O(1)
std::unordered_map<int, int> mymap = {
{ 1, 1},
{ 100, 2},
{ 100000, 3 }
};
我很好奇的是迭代存储在地图中的所有(未排序的)值需要多长时间 - 例如
for ( auto it = mymap.begin(); it != mymap.end(); ++it ) { ... }
我可以假设每个存储的值只被访问一次(或两次或恒定次数)吗?这意味着迭代所有值都在N值映射O(N)中。另一种可能性是我的密钥{1,10,100000}的例子最多需要1000000次迭代(如果用数组表示)
是否还有其他容器,可以线性迭代并且不断地通过给定密钥访问值?
我真正需要的是(伪代码)
myStructure.add(key, value) // O(1)
value = myStructure.at(key) // O(1)
for (auto key : mySructure) {...} // O(1) for each key/value pair = O(N) for N values
std :: unordered_map是我需要的结构吗?
整数索引也足够,平均复杂度也很高。
答案 0 :(得分:13)
无论它们是如何实现的,标准容器都提供满足迭代器要求的迭代器。递增迭代器需要是恒定时间,因此遍历任何标准容器的所有元素都是O(N)。
答案 1 :(得分:3)
有一些不同的方法可以实现哈希表,如果你感兴趣,我建议你阅读更多关于这些的方法,但主要的两个是通过链接和开放寻址。
在第一种情况下,您有一系列链接列表。数组中的每个条目都可以为空,哈希表中的每个项都位于某个存储桶中。因此,迭代沿着数组向下走,并沿着它中的每个非空列表向下走。显然是O(N),但根据链表本身的分配方式,可能会非常低效。
在第二种情况下,你只有一个非常大的数组,它将有很多空插槽。在这里,迭代再次显然是线性的,但如果表大部分为空(这应该用于查找目的),则效率可能很低,因为实际存在的元素将位于不同的高速缓存行中。
无论哪种方式,你都会进行线性迭代,而你将完全触及每个元素一次。请注意,std::map
也是如此,迭代在那里也是线性的。但是在地图的情况下,迭代肯定远没有迭代矢量的效率,所以请记住这一点。如果您的用例涉及要求快速查找和快速迭代,如果您预先插入所有元素并且永不擦除,那么实际上同时拥有地图和矢量可能会好得多。占用额外的空间以增加性能。
答案 2 :(得分:3)
所有标准容器的复杂性保证在C++ Standard中指定。
std::unordered_map
元素访问和元素插入的平均复杂度O(1)
和O(N)
最差情况(参见第23.5.4.3和23.5.4.4节;第797-798页) )。
特定实现(即特定供应商的标准库实现)可以选择他们想要的任何数据结构。但是,为了符合标准,它们的复杂性必须至少指定。