繁体   English   中英

std :: unordered_set迭代器遍历的复杂性

[英]Complexity of std::unordered_set iterator traversal

我最近玩了一个std::unordered_set 我怀疑我的版本的STL会跟踪一些FILO数据结构中的非空桶(看起来像一个列表)。 我想这样做是为了提供完整的std::unordered_set O(n)时间遍历(其中n表示具有m桶且m远大于nunordered_set的元素个数)。 这改善了在O(m)时间内所有桶的天真遍历。

我已经测试过,确实遍历大型且非常稀疏的unordered_set (带有begin - end )比所有桶的天真遍历要快得多。

问题 :这个遍历运行时是否由标准保证? 或者这只是我特定标准库的一个功能?


这是我的测试代码:

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

void test(vector<int> data, int alloc_size) {
   unordered_set<int> set(alloc_size);
   for (auto i: data) {
      set.insert(i);
   }

   for (size_t bidx = 0; bidx < set.bucket_count(); ++bidx) {
      cout << "[B" << bidx << ":";
      for (auto bit = set.begin(bidx); bit != set.end(bidx); ++bit) {
         cout << " " << *bit;
      }
      cout << "] ";
   }

   cout << "  {";
   for (auto const & d: set) {
      cout << d << " ";
   }
   cout << "}" << endl;
}

int main() {
   test({1, 2, 0}, 3);
   test({1, 2, 0, 7}, 3);
   test({18, 6, 11, 3, 13, 4}, 20);
   test({18, 6, 11, 3, 13, 4, 34}, 20);
}

哪个印刷品:

[B0: 0] [B1: 1] [B2: 2] [B3:] [B4:]   {0 2 1 }
[B0: 0] [B1: 1] [B2: 7 2] [B3:] [B4:]   {0 7 2 1 }
[B0:] [B1:] [B2:] [B3: 3] [B4: 4] [B5:] [B6: 6] [B7:] [B8:] [B9:] [B10:] [B11: 11] [B12:] [B13: 13] [B14:] [B15:] [B16:] [B17:] [B18: 18] [B19:] [B20:] [B21:] [B22:]   {4 13 3 11 6 18 }
[B0:] [B1:] [B2:] [B3: 3] [B4: 4] [B5:] [B6: 6] [B7:] [B8:] [B9:] [B10:] [B11: 34 11] [B12:] [B13: 13] [B14:] [B15:] [B16:] [B17:] [B18: 18] [B19:] [B20:] [B21:] [B22:]   {4 13 3 34 11 6 18 }

似乎begin - end遍历以相反的顺序报告桶,它们变为非空(参见第一行和第三行)。 插入已经非空的桶不会改变此顺序(参见第二行和第四行)。

简而言之:是的,这是由标准保证的。

说明

所有迭代器都需要具有O(n)遍历时间复杂度(其中n是遍历的项目数)。 这是因为迭代器上的每个操作都具有恒定的时间复杂度( O(1) ),包括将迭代器推进到一个位置。

根据标准(第24.2.1节第8节):

所有迭代器类别仅需要在恒定时间内(摊销)可以为给定类别实现的那些函数。 因此,迭代器的需求表没有复杂性列。

因此,当迭代std::unordered_set的项时,时间复杂度为O(n)n为集合中的项目数)。

不相信?

对上述引用的字面读数仅保证可实现恒定时间操作。 这并不妨碍特定实现具有比可实现的更复杂的时间复杂度。 这可能是一个糟糕的选择,并希望没有严肃的实现实际上这样做。

标准中唯一可以帮助解决这种歧义的地方是在第24.4.4节第1节中,标准对此有关std::advancestd::distance说法:

这些函数模板使用+-用于随机访问迭代器(因此,它们是恒定的时间); 对于输入,转发和双向迭代器,它们使用++来提供线性时间实现。

因此,前向迭代器上的++操作(用于std::unordered_set )暗示为常量时间操作。

总之,虽然第一个引用的措辞含糊不清,但第二个引用确认了意图。

暂无
暂无

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

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