Sortowanie szybkie (quicksort)

WPROWADZENIE

Sortowanie szybkie to poprawiony algorytm sortowania bąbelkowego. Podstawowa wersja algorytmu została wynaleziona w 1960 roku przez Hoare'a i od tego czasu był intensywnie badany. Stosowana jest zasada dziel i zwyciężaj. Algorytm jest klasy O(n log n) w typowych sytuacjach, oraz O(n^2) w najgorszym przypadku. Jako element podziału wybiera się element: środkowy, pierwszy, ostatni, losowy, medianę, medianę z trzech (chodzi o zapobieganie niekorzystnym przypadkom). Element podziału trafia od razu na swoje miejsce. Algorytm jest niestabilny.


# Wersja wg Kernighana i Ritchiego.

def quicksort(L, left, right):
    if left >= right:
        return
    swap(L, left, (left + right) // 2)   # element podziału
    pivot = left                      # przesuń do L[left]
    for i in range(left + 1, right + 1):   # podział
        if L[i] < L[left]:
            pivot += 1
            swap(L, pivot, i)
    swap(L, left, pivot)     # odtwórz element podziału
    quicksort(L, left, pivot - 1)
    quicksort(L, pivot + 1, right)

# Wersja wg Cormena.

def quicksort(L, left, right):
    """Sortowanie szybkie wg Cormena str. 169."""
    if left >= right:
        return
    pivot = partition(L, left, right)
    # pivot jest na swoim miejscu.
    quicksort(L, left, pivot - 1)
    quicksort(L, pivot + 1, right)

def partition(L, left, right):
    """Zwraca indeks elementu rozdzielającego."""
    # Element rozdzielający to ostatni z prawej,
    # dlatego na końcu trzeba go przerzucić do środka.
    # Będzie on na docelowej pozycji ze względu na sortowanie.
    x = L[right]   # element rozdzielający
    i = left
    for j in range(left, right):
        if L[j] <= x:
            swap(L, i, j)
            i += 1
    swap(L, i, right)
    return i

Algorytm można przyspieszyć wywołując dla małych ciągów inną metodę sortowania, np. insertsort().


# Typowo m wynosi między 5 a 25.
if (right - left) <= m:
    insertsort(L, left, right)