簡體   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