所有元素std :: unordered_map与std :: map的迭代性能差异?

时间:2019-06-30 14:26:50

标签: c++ c++11 stl

我想以指针作为键来映射数据。我应该选择哪个容器,映射或unordered_map?关于该主题,有很多关于stackoverflow的问题,但是当我们需要遍历所有键值对时,没有一个涉及性能方面的问题。

std::map<classKey* , classData*> myMap;
std::unordered_map<classKey* , classData*> myUnorderedMap;

for (auto & iter : myMap) { //loop1
    display(iter.second);
}

for (auto & iter : myUnorderedMap) { //loop2
    display(iter.second);
}

loop1 vs loop2可以提供更好的性能。 Bench Mark由@ RetiredNinja

提供

对于大小= 10,000,000,我们得到以下基准结果:

enter image description here

1 个答案:

答案 0 :(得分:5)

如您所料,这在很大程度上取决于标准库数据结构的实际实现。因此,这个答案将更加理论化,并且与任何一种实现方式无关。

std::map在幕后使用了平衡的二叉树。这就是为什么它具有O(log(n))插入,删除和查找的原因。对其进行迭代应该是线性的,因为您只需要进行深度优先遍历(这将需要O(log(n))内存,以堆栈空间的形式)。使用std::map进行迭代的好处是您可以按排序顺序遍历键,并且可以“免费”获得该好处。

std::unordered_map在表底使用哈希表。这使您可以摊销固定时间的插入,删除和查找。如果未针对迭代优化该实现,则幼稚的方法将是遍历哈希表中的每个存储桶。由于良好的哈希表(理论上)在50%的存储桶中仅包含一个元素,而在其余存储桶中仅包含零个元素,因此此操作也将是线性的。但是,与std::map的相同线性操作相比,它将花费更多的“挂钟时间”。为了解决这个问题,一些哈希表实现保留了所有元素的边列表以进行快速迭代。在这种情况下,在std::unordered_map上进行迭代会更快,因为您无法获得比在连续内存上进行迭代(显然仍然是线性时间)更好的方法。

在极不可能的情况下,您实际上需要优化到这个级别(而不是仅仅对理论上的性能感到好奇),您的代码中的其他地方可能会有更大的性能瓶颈。

所有这些都忽略了从指针值中删除键的可能性,但这既不存在也不存在。

进一步阅读资料的来源:

GCC std::map implementation

GCC std::unordered_map implementation

How GCC std::unordered_map achieves fast iteration