【问题标题】:How is iterating through a hashtable implemented?遍历哈希表是如何实现的?
【发布时间】:2012-12-22 04:57:48
【问题描述】:

我试图了解如何实现对哈希表的迭代。我只是无法想象。我对这种迭代的速度特别感兴趣。例如:

QHash<int, std::string> hashTable;
...
for (auto it = hashTable.begin(); it != hashTable.end(); ++it)
    std::cout << it.value() << std::endl;

这是O(hashTable.size()) 操作吗?

我试图挖掘源代码,但找不到正确的定义。

【问题讨论】:

    标签: c++ qt hash iterator complexity-theory


    【解决方案1】:

    哈希表的一些实现还维护所有条目的链接列表以允许快速迭代(所谓的“链接哈希映射”)。

    如果他们不这样做,唯一的方法是遍历哈希表的所有桶,同时也遍历每个桶中的元素。

    此操作的速度取决于表格的填充状态。当它非常低时,需要迭代很多空桶,这很浪费时间。当表格填得很好,并且每个桶中有一个或多个元素时,这几乎就像迭代一个链表。在每个桶只包含一个元素的完美哈希映射上,这就像迭代一个数组。

    【讨论】:

    • 是的,与桶数成线性关系 + 与条目数成线性关系。
    • 你的for循环相当于STL算法std::for_each。该算法在被访问的元素数量上是线性的。此外,std::unordered_map 容器至少有一个前向迭代器,并且对此类迭代器的所有操作至多是摊销常数。这意味着整个哈希表上的循环也具有线性时间复杂度(而不仅仅是线性大小复杂度)。
    • 对迭代器的要求是 IMO 不幸的。这意味着从技术上讲,如果您编写一个返回某些 BigNum 类型的“连续幂迭代器”,每次递增迭代器时加倍,并将其传递给标准算法,那么您将有未定义的行为。不仅比预期慢,UB。如果算法的复杂性保证用迭代器操作的数量以及谓词操作/副本/其他的数量来表示,那么可以定义行为。但它们不是,它们需要摊销的常量迭代器操作。
    猜你喜欢
    • 2014-01-21
    • 1970-01-01
    • 2013-02-25
    • 2014-06-01
    • 1970-01-01
    • 2012-04-21
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多