Standard C++ wymaga, aby std::partition
miał różną liczbę aplikacji predykatów między ForwardIterator
i BidirectionalIterator
. Dla wersji ForwardIterator
liczba aplikacji bazowych będzie < = N, gdzie N = std::distance(first, last)
, ale dla wersji BidirectionalIterator
liczba aplikacji źródłowych powinny być < = N/2. Oczywiście, obie wersje mają złożoność czasową O (N).Dlaczego standard C++ wymaga std :: partition w celu spełnienia różnych złożoności dla różnych typów iteratorów?
Moje pytanie brzmi: dlaczego warto zadawać różne wymagania dla różnych typów iteratorów? Takie wymaganie zmusza wiele kompilatorów?
np. MSVC, zaimplementuj funkcję std::partition
na dwa sposoby, aby spełnić takie wymagania, co nie wydaje się być bardzo eleganckie.
Kolejne pytanie: Czy istnieje jakiś algorytm, który opiera się na tego współczynnika, tak, że gdy N/2 staje N, asymptotycznej złożoności będzie inaczej? Dla mojego zrozumienia, jeśli weźmiemy pod uwagę Master's Theorem
, dla formularza w T(n) = aT(n/b) + f(n)
, współczynnik w f(n)
nie ma znaczenia.
C.f. Równoważny wdrożenie partycji msvc za:
template<class BidirIt, class UnaryPred>
BidirIt partition(BidirIt first, BidirIt last, UnaryPred pred, std::bidirectional_iterator_tag)
{
while (true)
{
while ((first != last) && pred(*first))
{
++first;
}
if (first == last)
{
break;
}
--last;
while ((first != last) && !pred(*last))
{
--last;
}
if (first == last)
{
break;
}
std::iter_swap(first, last);
++first;
}
return first;
}
template<class ForwardIt, class UnaryPred>
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred pred, std::forward_iterator_tag)
{
first = std::find_if_not(first, last, pred);
if (first == last)
{
return first;
}
for (ForwardIt src = std::next(first); src != last; ++src)
{
if (pred(*src))
{
std::iter_swap(first, src);
++src;
}
}
return first;
}
template<class ForwardIt, class UnaryPred>
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred pred)
{
return partition(first, last, pred, typename std::iterator_traits<ForwardIt>::iterator_category());
}
Dziękuję bardzo za odpowiedź na moje pytanie. Jak wskazano, popełniłem błąd w liczbie aplikacji predykatów. Obie wersje są przeznaczone do aplikacji * N *. Jest to liczba różnych swapów. Teraz mogę zrozumieć, że standard wymaga tak, ponieważ jest to optymalny wymóg. Jeszcze raz dziękuję za miłe odpowiedzi. :) –
Nie ma za co. Proszę zaznaczyć odpowiedź jako zaakceptowaną, jeśli odpowiada na twoje pytanie. – michalsrb