[英]Asymptotic complexity of std::remove_if
我正在為一種具有硬編碼最大元素數N的數據結構的擦除方法而工作,該方法依賴於std::array
來避免堆內存。 盡管std::array
僅包含N個元素,其中M個是“相關的”元素,其中M小於或等於N。例如,如果N為10,則數組如下所示:
std::array<int, N> elements = { 0, 1, 2, -1, 4, -1, 6, -1, -1, 9 };
...如果M為7,則只有前7個元素是“相關的”,而其他元素則被視為垃圾(結尾{ -1, -1, -9 }
是垃圾)。 我在這里將int
用於SO示例,但實際程序存儲了實現operator==
對象。 下面是一個有效的示例,該示例刪除所有-1
並更新M:
#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_if
和std::distance
是整體O(2M)或O(M),其中std::remove_if
是更昂貴的操作。 但是我不確定std::remove_if
是否為O(N * M),因為每個刪除操作都會移動元素
編輯 :為清楚起見,我理解這應該將謂詞應用M次,但我想知道每次謂詞為真時是否都應用N個移位
通過cppreference :
復雜度 :謂詞的
std::distance(first, last)
精確應用。
對移除的元素沒有移位操作,因為在調用std::remove_if
之后它們可以具有未指定的值
編輯
回想起來,這個答案解決了一個比所提問題還要復雜的問題:如何在線性時間內實現“推回端”功能。 關於所要求的特定問題-與remove_if
有關-@millenimumbug的答案可以更好地解決該問題。
我可以看到為什么您會認為復雜度為Θ(mn) ,因為m個移除的項目中的每一個可能都需要移動Θ(n)距離。
實際上有可能在時間Θ(n)和額外的O(1)空間(僅幾個額外的迭代器)中執行此操作。
考慮下圖,該圖顯示了算法的可能實現的迭代。
紅色項目是已識別項目的連續組,將要刪除到此為止(您只需要兩點即可記錄下來)。 綠色項目是現在正在考慮的項目(另一個指針)。
如果要刪除綠色項,則將紅色組包括在內就變得更大。 下圖顯示了該圖,紅色組在其中展開。 在下一次迭代中,綠色項目將在其右側。
如果不是,則所有紅色組都需要移過它。 有些想法可以說服您,這可以在紅色組的線性時間內完成(即使保證迭代器僅是正向迭代器)。
為什么復雜度是線性的? 因為您可以想象這等同於綠色元素相對於左組向左移動。 基本原理類似於攤銷分析的基本原理。
下圖顯示了第二種情況。 在下一次迭代中,綠色元素(正在考慮)將再次位於紅色組的右側。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.