2016-08-11 52 views
1

我正在研究數據結構的擦除方法,該數據結構具有硬編碼的最大元素數N,它依賴於std::array來避免堆內存。雖然std::array包含N個元素只有一些數目M,都是「相關的」元素,其中M小於或等於N.作爲一個例子,如果N是10和陣列看起來像這樣:漸進複雜度std :: remove_if

std::array<int, N> elements = { 0, 1, 2, -1, 4, -1, 6, -1, -1, 9 }; 

...如果M是7,則只有前7個元素是「相關」,而其他元素被認爲是垃圾(結尾{ -1, -1, -9 }是垃圾)。我在這裏使用int來舉例,但真正的程序存儲實現operator==的對象。下面是一個工作的例子,刪除所有-1和更新瑪:

#include <algorithm> 
#include <array> 
#include <iostream> 

constexpr unsigned N = 10; 
unsigned   M = 7; 
std::array<int, N> elements = { 0, 1, 2, -1, 4, -1, 6, -1, -1, 9 }; 

int main() { 
     for (unsigned i = 0; i < M; ++i) 
       std::cout << elements[i] << ' '; 
     std::cout << '\n'; 

     auto newEnd = std::remove_if(
       std::begin(elements), std::begin(elements) + M, 
       [](const auto& element) { 
         return -1 == element; 
       } 
     ); 

     unsigned numDeleted = M - std::distance(std::begin(elements), newEnd); 
     M -= numDeleted; 
     std::cout << "Num deleted: " << numDeleted << '\n'; 

     for (unsigned i = 0; i < M; ++i) 
       std::cout << elements[i] << ' '; 
     std::cout << '\n'; 

     return 0; 
} 

我的問題是什麼是std::remove_if的漸近複雜性?我會想象在std::remove_ifstd::distance之間,總體上是O(2M)或O(M),其中std::remove_if是更昂貴的操作。但是我不知道如果std::remove_if是O(N * M)由於每缺失移元件

編輯:爲了清楚起見,我明白,這應該被應用謂詞M次但如果N位移是想知道被每次謂詞是真

+0

反正'的std ::開始(元素),&元素[M]'是實現自C++標準說,'的std ::開始(元素)'將返回'elements.begin特定行爲()' ,它又返回一個'std :: array :: iterator',它是實現特定類型的,'&elements [M]'是一個指針類型 – Danh

+0

@Danh,它怎麼可能是O(1)?如果我有一個大小爲100的數組,90個元素是「相關的」,我認爲90是M,那麼'std :: remove'至少是O(M) – asimes

+1

@Danh複雜性肯定不是'O 1)',因爲它依賴於'N'和'M',使它們保持不變不會改變程序的複雜性取決於這兩個值的事實。 – Holt

回答

2

編輯

這個答案,現在回想起來,解決了超過一個更復雜的問題是什麼被問 - 在線性時間內如何實現「推回到終止」功能?關於被問到的具體問題 - 有關remove_if - @ millenimumbug的答案更好地解決了這個問題。


我能明白你爲什麼會覺得複雜性將是Θ(M n)爲,因爲每個刪除的項目可能需要轉移Θ(N)距離。

它實際上是有可能做到這一點的時候Θ(N)和附加O(1)空間(只需幾個迭代器)。

考慮下圖,顯示算法的可能實現的迭代。

enter image description here

紅色的物品是認可項目的一組連續的被刪除到結束,在這一點上(你只需要兩個點來記錄這一點)。綠色項目是正在考慮的項目(另一個指針)。

如果綠色項目將被刪除,紅色組通過包含它而變得更大。下圖顯示了紅色組的擴展。在下一次迭代中,綠色項目將成爲它的右側。 enter image description here

如果不是,則所有紅色組都需要移過它。有些想法可以說服你,這可以在紅組中以線性時間完成(即使迭代器保證只是前向迭代器)。

爲什麼複雜度是線性的?因爲你可以想象這相當於綠色元素相對於左側組左移。其基本原理與攤銷分析類似。

下圖顯示了第二種情況。在下一次迭代中,綠色元素(正在考慮)將再次位於紅色組的右側。

enter image description here

+0

假設有一個以上的紅色組,或者真的很討厭,其他每個元素都是紅色的。我很難看到如何避免向右移動所有元素 – asimes

+0

@asimes紅色組在此迭代中僅顯示*識別的*將被移除的元素。很可能在綠點的右側,交替的元素將被移除或不移除。從概念上講,每一個將被刪除的紅色部分都會增長。每一個在概念上都不會被移除的將被移到左邊(因爲這些是前向迭代器,紅色實際上會移過它,但這樣更容易看出複雜性)。 –

+0

我認爲可能需要O(M)空間,但這是一個很好的答案。我可以看到現在如何在O(M)時間內實現這一點 – asimes

4

施加通過cppreference

複雜:謂詞 究竟std::distance(first, last)應用程序。

上有刪除的元素無移位操作,因爲他們可以有通話結束後未指定值std::remove_if

+1

引用指定謂詞的應用程序數量,而問題具體詢問有關移位操作的數量。 –

+0

雖然它在0和M之間迭代,但是整體數據結構的長度爲N.也許我應該在我的問題中更多地強調它,但是我想知道的是N個移位的可能性(而不是謂詞的M個應用程序) – asimes

+0

@asimes'std :: remove_if'不關心底層數組,它唯一知道的是'std :: distance(first,last)== M',所以它保證在'O(M) '。如果你有一個帶'.size()= M'和'.capacity()= N'的向量,'std :: remove_if'運行在'O(M)'而不是'O(N)'上,它是一樣的這裏的想法。 – Holt