Programování
Quick sort
Jak již název napovídá, Quicksort je rychlý. On je dokonce
nejrychlejší a je to algoritmus, který se skutečně používá v praxi k
třídění prvků, proto bude tento článek o něco obsáhlejší, než
ostatní. Chová se dobře jak na malých, tak na velkých polích a je
paměťově nenáročný. Algoritmus je založen na principu rozděl a
panuj, který jsme si již vysvětlili v algoritmu Merge
sort.
Quicksort si označí jeden prvek v poli jako tzv. pivot.
Výběrem pivotu se prozatím nebudeme zabývat a budeme jako pivot brát vždy
první prvek v poli. Nyní zavoláme funkci divide (rozděl),
která přeuspořádá pole tak, aby byly zleva prvky menší než pivot, poté
následovat pivot sám a za pivotem byly prvky větší, než je on sám.
Povšimněte si, že jsem napsal přeuspořádá, nikoli setřídí. Prvky jsou
tedy mezi sebou stále rozházené a jediné setřídění spočívá v jejich
rozdělení pivotem. Tuto operaci jsme schopni zvládnout v lineárním čase a
také velmi rychle. Nyní algoritmus rekurzivně zavoláme na levou polovinu
pole před pivotem a na pravou polovinu za pivotem (pivota už necháme tam, kde
je). S těmi provedeme to samé, jako s původním polem a takto budeme
pokračovat až do chvíle, kdy na vstupu dostaneme jednotkové pole (pole
velikosti 1). Po vynoření z rekurze nemusíme dělat už vůbec nic, pole je
setříděné. Nyní si algoritmus předvedeme v praxi a řekneme si více o
funkci rozděl.
Není Stabilní
Na místě
O (n²)
Velmi rychlý
Omicron: n²
Omega: n log n
Theta: n²
Průběh
Protože Quicksort je velmi rychlý, předvedeme si ho tentokrát na poli o
trochu větším, než obvykle, abychom z něj něco vůbec viděli
Máme tedy pole následujících prvků:
Jako první si musíme vybrat pivot, ten si vybereme tak, že vezeme první prvek, prostřední prvek a poslední prvek, který seřadíme a vybereme ten prostřední jako pivot.
Teď budeme kontrolovat pivot s prvkama z leva a zprava a zastavime se pokud najdeme potvrzeni pravidla
Zprava je menší jak pivot
Zleva je větší jak pivot
Našla se shoda v obou prvkách, takže je prohodíme
Pokračujeme dál v kontrole
Kontrola se ukončí jakmile počítadlo z leva je větší jak zprava a prohodíme předmět z levého počítadla s pivotem.
Jelikož je celá funkce rekurzivní tak se ted pole rozdělí na dvě části a to na 3, 2, 1 a 8, 5, 9. Které budou dělat uplně to samé jako původní pole.
Počítadlo zleva je větší jak zprava, takže prohodíme pivot s počítadlem zleva.
Počítadlo zleva je větší jak zprava, takže prohodíme pivot s počítadlem zleva.
+
+
5 | 2 | 9 | 3 | 5 | 1 | 8 |
Vybereme 3 | ||||||
---|---|---|---|---|---|---|
5 | 2 | 9 | 3 | 5 | 1 | 8 |
Uspořádáme 3 vybranné prvky | ||||||
---|---|---|---|---|---|---|
3 | 2 | 9 | 5 | 5 | 1 | 8 |
Prostřední prvek jako pivot | ||||||
---|---|---|---|---|---|---|
3 | 2 | 9 | 5 | 5 | 1 | 8 |
Pivot půjde na konec
3 | 2 | 9 | 5 | 5 | 1 | 8 |
—>
3 | 2 | 9 | 8 | 5 | 1 | 5 |
Teď budeme kontrolovat pivot s prvkama z leva a zprava a zastavime se pokud najdeme potvrzeni pravidla
Zprava je menší jak pivot
Zleva je větší jak pivot
3 > 5 🚫 ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 9 | 8 | 5 | 1 | 5 |
↑ 1 < 5 ✅ |
2 > 5 🚫 ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 9 | 8 | 5 | 1 | 5 |
↑ 1 < 5 ✅ |
9 > 5 ✅ ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 9 | 8 | 5 | 1 | 5 |
↑ 1 < 5 ✅ |
3 | 2 | 1 | 8 | 5 | 9 | 5 |
8 > 5 ✅ ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 1 | 8 | 5 | 9 | 5 |
↑ 5 < 5 🚫 |
8 > 5 ✅ ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 1 | 8 | 5 | 9 | 5 |
↑ 8 < 5 🚫 |
8 > 5 ✅ ↓ |
||||||
---|---|---|---|---|---|---|
3 | 2 | 1 | 8 | 5 | 9 | 5 |
↑ 1 < 5 ✅ |
↓ | ||||||
---|---|---|---|---|---|---|
3 | 2 | 1 | 8 | 5 | 9 | 5 |
—>
↓ | ||||||
---|---|---|---|---|---|---|
3 | 2 | 1 | 5 | 5 | 9 | 8 |
Vybereme 3 | ||||||
---|---|---|---|---|---|---|
3 | 2 | 1 |
Uspořádáme 3 vybranné prvky | ||||||
---|---|---|---|---|---|---|
1 | 2 | 3 |
Pivot je uprostřed | ||||||
---|---|---|---|---|---|---|
1 | 2 | 3 |
Pivot jde na konec | ||||||
---|---|---|---|---|---|---|
1 | 3 | 2 |
1 > 2 🚫 ↓ |
||
---|---|---|
1 | 3 | 2 |
↑ 3 < 2 🚫 |
3 > 2 ✅ ↓ |
||
---|---|---|
1 | 3 | 2 |
↑ 1 < 2 ✅ |
Vysledek | ||||||
---|---|---|---|---|---|---|
1 | 2 | 3 |
Vybereme 3 | ||||||
---|---|---|---|---|---|---|
8 | 5 | 9 |
Uspořádáme 3 vybranné prvky | ||||||
---|---|---|---|---|---|---|
5 | 8 | 9 |
Pivot je uprostřed | ||||||
---|---|---|---|---|---|---|
5 | 8 | 9 |
Pivot jde na konec | ||||||
---|---|---|---|---|---|---|
5 | 9 | 8 |
5 > 8 🚫 ↓ |
||
---|---|---|
5 | 9 | 8 |
↑ 9 < 8 🚫 |
9 > 8 ✅ ↓ |
||
---|---|---|
5 | 9 | 8 |
↑ 5 < 8 ✅ |
Vysledek | ||||||
---|---|---|---|---|---|---|
5 | 8 | 9 |
Všechny výsledky dáme dohromady a máme výsledek
1 | 2 | 3 |
5 |
5 | 8 | 9 |
1 | 2 | 3 | 5 | 5 | 8 | 9 |
Kod
public static void QuickSort(int[] data, int start = 0, int end = -1)
{
if (end < 0)
end = data.Length;
if (start + 1 >= end)
return;
int boundary = start + 1;
for (int i = boundary; i < end; i++)
{
if (data[i] < data[start])
{
Swap(i, boundary, data);
boundary++;
}
}
Swap(start, boundary - 1, data);
QuickSort(data, start, boundary - 1);
QuickSort(data, boundary, end);
}
public static void Swap(int a, int b, int[] data)
{
int tmp = data[a];
data[a] = data[b];
data[b] = tmp;
}
Video
Zdroj: Video Link