2013-04-28 8 views
5

mam trywialne wdrożenie quicksort, że idzie przez:Jaką magię używa `std :: sort` wewnętrznie, co sprawia, że ​​jest o wiele szybsza?

template <typename IteratorType> 
void quicksort(IteratorType begin, IteratorType end) 
{ 
    if (begin != end) 
    { 
    const auto pivot = *(begin + distance(begin, end)/2); 
    const IteratorType sep = std::partition(begin, end, [pivot](typename IteratorType::value_type v){ return (v < pivot); }); 

    if (sep != begin) 
    { 
     quicksort(begin, sep); 
    } 

    if (sep != end) 
    { 
     quicksort(sep + 1, end); 
    } 
    } 
} 

testowanie go na 1000000 elementów tablicy odbywa się zawsze (6300 ms) przed czasem umierają z rekurencji, natomiast std::sort trwa jak 30 ms.

Z pewnością nie spodziewam się, że moja ponura implementacja będzie tak szybka jak std::sort, ale jak może istnieć tak ogromna różnica?

Rozumiem, że std::sort używa czegoś bardziej skomplikowanego niż prosty quicksort (uważam, że jest introsort), który zapobiega zbyt daleko na poziomie rekurencji i tym podobnym. Ale czy jest coś oczywistego, co może mi wyjaśnić tak wielką różnicę?

Zróżnicowanie wielkości arii pokazuje, że współczynnik różnicy nie jest stały, tak naprawdę rośnie on jak .

+1

Implementacja dla libstdC++ rozpoczyna się na linii 5207 od [std_algo.h] (http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.4/a01347.html#l05207). –

+0

@bamboon: Tak naprawdę przeczytałem to pytanie (i jego odpowiedzi). Nie jestem pewien, czy to jest dokładnie podobne. Moją główną troską jest wyjaśnienie różnic na poziomie wdrażania, a nie na poziomie funkcjonalnym. – ereOn

+0

Cóż, masz dość standardową implementację quicksort, która ma nawet najgorszy możliwy czas działania O (n^2), w który możesz przechwycić pułapkę. Ponadto pytanie może lepiej pasować do http://codereview.stackexchange.com/. – inf

Odpowiedz

1

Najpierw sprawdź lepszy wybór przestawny (zwykle używana jest mediana 3) i wyeliminuj jedną gałąź rekursji, aby zaoszczędzić miejsce na stosie.

Wybór pivot ma największy wpływ na ogólną wydajność algorytmiczną, ponieważ odróżnia N * log (n) od N^2.

1

Zakładając, że kod jest poprawny (quicksort może być trudny), to myślę, że duża różnica polega na tym, że nie używasz szybszego sortowania, gdy liczba elementów jest mała. Na przykład często stosuje się sortowanie selekcji, gdy liczba elementów do posortowania jest mniejsza niż niewielka liczba.

Ten podejrzany kod C++ 11 również mnie podejrzewa, chociaż przyznaję, że nic o tym nie wiem.

+0

Tak, to jest dobry punkt, ale jest to sortowanie wstawiania, a nie sortowanie sortowania, które jest tam używane. Dzieje się tak dlatego, że sortowanie selekcji jest zawsze w O (N^2) dla liczby porównań, podczas gdy sortowanie z wstawkami ma najlepszy przypadek w O (N). – ltjax

Powiązane problemy