簡體   English   中英

刪除向量和雙端隊列中的項目的時間復雜度

[英]Time complexity of removing items in vectors and deque

我已經讀過,在std::vector末尾添加項目的時間復雜度是分攤常量,並且在std::deque的頂部和底部插入項目是常量。因為這兩個容器都有一個隨機訪問迭代器,因此訪問元素任何指數都是不變的。 如果我有任何這些事實錯誤,請告訴我。我的問題是,如果訪問std::vectorstd::deque的元素是常量,那么為什么通過擦除O(n)刪除元素的時間復雜度。 這里的答案之一指出通過擦除元素是O(n)。 我知道擦除會刪除起始迭代器和結束迭代器之間的元素,所以答案基本上意味着它的O(n)取決於兩個迭代器之間的元素的數量,並且從任何向量/雙端隊列中刪除單個元素指數會為零?

std::vectorstd::deque情況有所不同,C ++ 98和C ++ 11也有所不同。

的std ::矢量

std::vector::erase()的復雜性與std::vector::erase()范圍的長度以及范圍的結尾和容器的末尾之間的元素數量是線性的(因此從末尾擦除元素需要不變時間)。

C ++ 2003 [lib.vector.modifiers]讀取:

iterator erase(iterator position);
iterator erase(iterator first, iterator last);`

...

復雜性: T的析構函數被稱為等於被擦除元素數量的次數,但T賦值運算符被稱為等於擦除元素之后的向量中元素數量的次數。

C ++ 14草案N4140 [vector.modifiers]讀取:

復雜性: T的析構函數被稱為等於被擦除元素數量的次數,但T移動賦值運算符被稱為等於擦除元素之后的向量中元素數量的次數。

因此,您可以看到C ++ 11/14實現通常更有效,因為它執行移動分配而不是復制分配,但復雜性保持不變。

的std ::雙端隊列

std::deque::erase()的復雜性與std::deque::erase()范圍的長度和兩個數字的最小值呈線性關系:范圍開始前剩余元素的數量,以及結束后剩余元素的數量范圍。 因此,從開頭或結束擦除元素需要恆定的時間。

C ++ 2003 [lib.deque.modifiers]

iterator erase(iterator position);
iterator erase(iterator first, iterator last);

復雜性:對析構函數的調用次數與擦除的元素數相同,但對賦值運算符的調用次數最多等於擦除元素之前的元素數量和元素數量的最小值擦除后的元素。

C ++ 14 draft N4140 [deque.modifiers]/5

復雜性:對析構函數的調用次數與擦除的元素數相同,但對賦值運算符的調用次數超過擦除元素之前的元素數量和之后的元素數量中的較小者。擦除元素。

所以,它在C ++ 98和C ++ 11/14中是相同的,除了C ++ 11可以在移動賦值和復制賦值之間進行選擇(這里我看到標准中的一些不一致,因為措辭沒有提到移動像std::vector這樣的賦值 - 可能是另一個問題的原因)。

還要注意措辭中的“最多”和“不再”。 這允許實現比線性更有效,但在實踐中它們是線性的( DEMO )。

刪除向量中的元素是O(n),因為一旦刪除元素,您仍需要移動所有連續元素以填充創建的間隙。 如果向量具有n個元素,那么在最壞的情況下,您將需要移位n-1個元素,因此復雜度為O(n)。

刪除元素確實是O(n)不是因為你需要做什么來找到要刪除的元素,而是因為你必須對它之后的所有元素做什么。 需要向下滑動這些元素以填充空槽。

因此,平均而言,擦除將在向量的中間占據一個元素,因此您必須移動大約一半的元素。 因此O(n) 最好的情況是,你刪除最后一個元素 - 不需要滑動。 最壞的情況是,你擦除第一個元素 - 然后必須移動每個其他元素。

通過使用這種方式時間復雜度=范圍長度+移位長度(n - 范圍結束)

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it, it+length);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM