Menu
Coddy logo textTech

Quicksort (sortowanie szybkie)

Ostatnia aktualizacja

Quicksort to algorytm typu dziel i zwyciężaj, który sortuje wokół elementu "pivot". Wybiera pivot, a potem dzieli tablicę tak, aby wszystko mniejsze znalazło się przed nim, a wszystko większe za nim, co ustala pivot na jego ostatecznej, posortowanej pozycji. Następnie rekurencyjnie sortuje lewą i prawą część. Ta wizualizacja używa schematu Lomuto z ostatnim elementem jako pivotem. Kliknij odtwarzanie i zobacz partycjonowanie oraz umieszczanie pivota.

Quicksort jest w praktyce zwykle najszybszym sortowaniem ogólnego przeznaczenia dzięki dobrej współpracy z pamięcią podręczną i partycjonowaniu w miejscu, średnio osiągając O(n log n). Jego najgorszy przypadek to O(n²) (np. już posortowana tablica przy złym wyborze pivota), którego unikają dobre strategie wyboru pivota, takie jak mediana z trzech czy losowanie.

Złożoność czasowa i pamięciowa

PrzypadekZłożonośćUwagi
Najlepszy przypadekO(n log n)Zrównoważone podziały
Średni przypadekO(n log n)Losowa kolejność
Najgorszy przypadekO(n²)Stale niezrównoważone pivoty
PamięćO(log n)Stos rekurencji (partycjonowanie w miejscu)
StabilneNieZamiany przy partycjonowaniu zmieniają kolejność równych elementów

Krok po kroku

KrokCo się dzieje
1Wybierz pivot (tutaj ostatni element zakresu).
2Partycjonowanie: przenieś wszystkie elementy mniejsze od pivota na jego lewą stronę.
3Zamień pivot na granicę podziału: jest teraz na ostatecznej pozycji.
4Rekurencyjnie posortuj quicksortem lewą część.
5Rekurencyjnie posortuj quicksortem prawą część.

Przykład krok po kroku

Sortowanie [5, 2, 4, 1] schematem Lomuto (ostatni element jako pivot):

PrzebiegTablicaDziałanie
Start[5, 2, 4, 1]Partycjonuj cały zakres; pivot to 1 (ostatni element).
1[1, 2, 4, 5]Nic nie jest mniejsze od 1, więc zamień 1 na indeks 0; pivot 1 jest teraz na swoim miejscu. Rekurencja w prawo na [2, 4, 5].
2[1, 2, 4, 5]Partycjonuj [2, 4, 5] z pivotem 5; zarówno 2, jak i 4 są mniejsze, więc 5 zostaje na końcu i jest na swoim miejscu. Rekurencja w lewo na [2, 4].
3[1, 2, 4, 5]Partycjonuj [2, 4] z pivotem 4; 2 jest mniejsze, więc 4 zostaje na miejscu i jest ostateczne. 2 to pojedynczy element, więc jest już posortowany.
Koniec[1, 2, 4, 5]Każdy pivot jest na swoim miejscu; tablica jest posortowana.

Kiedy używać quicksorta

Używaj, gdyUnikaj, gdy
Potrzebujesz szybkiego sortowania w pamięci ogólnego przeznaczenia z małymi stałymi.Potrzebujesz gwarantowanego czasu O(n log n) w najgorszym przypadku (użyj heap sort lub merge sort).
Pamięci jest mało: partycjonowanie działa w miejscu i potrzebuje tylko O(log n) pamięci na stos.Potrzebujesz stabilnego sortowania, które zachowuje kolejność równych kluczy.
Dane mają losową lub nieznaną kolejność, a używasz losowego pivota lub mediany z trzech.Dane są już posortowane lub prawie posortowane, a pivot jest stały, co wywołuje O(n²).
Liczy się dobra lokalność pamięci podręcznej, bo quicksort odczytuje pamięć sekwencyjnie.Sortujesz listę jednokierunkową, gdzie merge sort nie potrzebuje dostępu swobodnego, na którym opiera się quicksort.

Quick Sort: kod

Przejrzysta, gotowa do uruchomienia implementacja algorytmu Quick Sort w językach: Python, JavaScript, Java, C++, C, Pseudocode. Wybierz język, skopiuj kod albo otwórz go od razu w edytorze online Coddy.

Quick Sort: kod (Python)

Python
1def quick_sort(a, low=0, high=None):2    if high is None:3        high = len(a) - 14    if low < high:5        p = partition(a, low, high)6        quick_sort(a, low, p - 1)7        quick_sort(a, p + 1, high)8    return a9
10
11def partition(a, low, high):12    # Lomuto partition: everything < pivot moves left of it13    pivot = a[high]14    i = low15    for j in range(low, high):16        if a[j] < pivot:17            a[i], a[j] = a[j], a[i]18            i += 119    a[i], a[high] = a[high], a[i]20    return i21
22
23nums = [10, 7, 8, 9, 1, 5]24print("Before:", nums)25quick_sort(nums)26print("After: ", nums)
Uruchom ten kod w edytorze Python online

Quicksort: najczęstsze pytania

Jaka jest złożoność czasowa quicksorta?
Quicksort średnio ma złożoność O(n log n) i O(n log n) w najlepszym przypadku, ale w najgorszym przypadku, gdy podziały są stale niezrównoważone, degraduje się do O(n²). Losowe pivoty lub mediana z trzech sprawiają, że najgorszy przypadek jest bardzo mało prawdopodobny.
Czy quicksort jest stabilny?
Nie. Standardowe partycjonowanie w miejscu zamienia odległe elementy, co może zmienić względną kolejność równych kluczy. Istnieją stabilne warianty, ale tracą przewagę quicksorta, jaką jest sortowanie w miejscu.
Dlaczego quicksort jest często szybszy od merge sort?
Quicksort partycjonuje w miejscu, świetnie korzystając z lokalności pamięci podręcznej i bez dodatkowego bufora, więc jego stałe są małe. Merge sort ma to samo ograniczenie O(n log n), ale płaci za bufor O(n) i więcej przenoszenia danych.
Quicksort czy merge sort: co wybrać?
Wybierz quicksort do szybkiego sortowania tablic w pamięci w miejscu, gdzie jego małe stałe zwykle wygrywają. Wybierz merge sort, gdy potrzebujesz stabilnego sortowania, gwarantowanego O(n log n) w najgorszym przypadku albo sortujesz listy jednokierunkowe lub dane zewnętrzne, które nie mieszczą się w RAM.
Dlaczego quicksort ma złożoność O(n²) na posortowanej tablicy?
Przy stałym pivocie, takim jak pierwszy lub ostatni element, już posortowane dane sprawiają, że każdy podział odcina tylko jeden element, co daje n poziomów rekurencji zamiast log n. Losowy wybór pivota lub mediana z trzech przełamują ten wzorzec i przywracają zachowanie O(n log n).
Czym różnią się schematy partycjonowania Lomuto i Hoare'a?
Schemat Lomuto używa jednego indeksu przesuwającego się od lewej do prawej i jest prostszy w implementacji, dlatego używa go ta wizualizacja. Schemat Hoare'a używa dwóch wskaźników zbliżających się do siebie i zwykle wykonuje mniej zamian, co czyni go szybszym w praktyce, ale nie umieszcza pivota na ostatecznej pozycji podczas partycjonowania.
Ilustracja języków programowania w Coddy

Opanuj algorytmy z Coddy

ZACZNIJ