繁体   English   中英

std :: unordered_set :: erase复杂性

[英]std::unordered_set::erase complexity

我不明白,为什么在最坏的情况下(其中N是元素的数量)有std :: unordered_set O(N)复杂度的擦除方法? 标准(n4296)表示擦除方法的所有三个版本在最坏情况下都具有O(a.size())复杂度( a是容器),并且仅使指向已擦除元素的迭代器无效,但不是所有迭代器(即重新散列不是发生)。 即使对于采用一个迭代器参数并且在平均情况下具有恒定复杂性的版本也是如此。 我认为这是因为擦除版本将迭代器返回到下一个元素,这需要在擦除元素之后找到第一个非空桶,并且它给出O(a.bucket_count())复杂度,但不是O(a.size) ())! 元素数量与桶数的比例不成正比。 例如:

#include <iostream>
#include <unordered_set>
using namespace std;

int main()
{
    std::unordered_set<int> aSet;
    aSet.insert ({125, 126});
    aSet.rehash (1000);
    cout << aSet.size() << endl;
    cout << aSet.bucket_count() << endl;
}

输出是

Size: 2
Bucket count: 1031

容器的大小只有2而bucket_count是1031.当调用erase方法时,它将寻找下一个非空桶,它可以放在最后,即复杂度为O(a.bucket_count()),但是不是O(a.size())。 什么是标准给出O(a.size())复杂性的原因?

即使对于采用一个迭代器参数并且在平均情况下具有恒定复杂性的版本也是如此。

无序关联容器具有前向迭代器 - 允许通过单链表实现它们。

擦除节点涉及将节点重新链接到节点之后的节点。 在迭代器指向的节点之前找到节点可能是基于单链接列表的实现中的最坏情况O(N) ,因为您基本上必须遍历存储桶(可以包含容器中的每个元素)完全碰撞的情况)。

最明显的原因是退化散列函数可能会为所有元素产生相同的值。 结果他们都被分到同一个桶里。 尽管不太可能,但即使具有相当好的散列函数, 也可能发生同样的情况,特别是在将值映射到桶之后。 由于没有合理的散列函数质量规范,标准不能要求更好的时间复杂度。

什么是标准给出O(a.size())复杂性的原因?

std::unordered_set是一个哈希容器。 如果提供的散列函数映射到插入容器的每个元素的相同值,则它们将被链接在一起(可能在链表中)。 因此,在最坏的情况下,单个“列表”可以包含容器中的所有项目,就像任何“查找”操作一样, erase在元素数量上更糟糕。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM