|
Serwis Edukacyjny Nauczycieli w I-LO w Tarnowie
Materiały głownie dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
Algorytm sortowania szybkiego opiera się na strategii "dziel i zwyciężaj" (ang. divide and conquer), którą możemy krótko scharakteryzować w trzech punktach:
Idea sortowania szybkiego jest następująca:
| DZIEL : | najpierw sortowany zbiór dzielimy na dwie części w taki sposób, aby wszystkie elementy leżące w pierwszej części (zwanej lewą partycją) były mniejsze lub równe od wszystkich elementów drugiej części zbioru (zwanej prawą partycją). |
| ZWYCIĘŻAJ : | każdą z partycji sortujemy rekurencyjnie tym samym algorytmem. |
| POŁĄCZ : | połączenie tych dwóch partycji w jeden zbiór daje w wyniku zbiór posortowany. |
![]() prof. Tony Hoare |
Sortowanie szybkie zostało wynalezione przez angielskiego informatyka,
profesora
Tony'ego Hoare'a w latach 60-tych ubiegłego wieku. W przypadku typowym algorytm ten jest najszybszym algorytmem sortującym z klasy
złożoności obliczeniowej
Do utworzenia partycji musimy ze zbioru wybrać jeden z elementów, który nazwiemy piwotem. W lewej partycji znajdą się wszystkie elementy niewiększe od piwotu, a w prawej partycji umieścimy wszystkie elementy niemniejsze od piwotu. Położenie elementów równych nie wpływa na proces sortowania, zatem mogą one występować w obu partycjach. Również porządek elementów w każdej z partycji nie jest ustalony.
Jako piwot można wybierać element pierwszy, środkowy, ostatni, medianę lub losowy. Dla naszych potrzeb wybierzemy element środkowy:
| piwot ← d[(lewy + prawy) div 2] |
|
Dzielenie na partycje polega na umieszczeniu dwóch wskaźników na początku zbioru - i oraz j. Wskaźnik i przebiega przez zbiór poszukując wartości mniejszych od piwotu. Po znalezieniu takiej wartości jest ona wymieniana z elementem na pozycji j. Po tej operacji wskaźnik j jest przesuwany na następną pozycję. Wskaźnik j zapamiętuje pozycję, na którą trafi następny element oraz na końcu wskazuje miejsce, gdzie znajdzie się piwot. W trakcie podziału piwot jest bezpiecznie przechowywany na ostatniej pozycji w zbiorze.
Przykład:
Dla przykładu podzielimy na partycje zbiór:
| Lp. | Operacja | Opis |
| 1. |
7 2 4 7 3 1 4 6 5 8 3 9 2 6 7 6 3
|
Wyznaczamy na piwot element środkowy. |
| 2. |
7 2 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 |
Piwot wymieniamy z ostatnim elementem zbioru |
| 3. |
7 2 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Na początku zbioru ustawiamy dwa wskaźniki. Wskaźnik i będzie przeglądał zbiór do przedostatniej pozycji. Wskaźnik j zapamiętuje miejsce wstawiania elementów mniejszych od piwotu |
| 4. |
7 2 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Wskaźnikiem i
szukamy elementu mniejszego od piwotu |
| 5. |
2 7 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Znaleziony element wymieniamy z elementem na pozycji j-tej. Po wymianie wskaźnik j przesuwamy o 1 pozycję. |
| 6. |
2 7 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 7. |
2 4 7 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 8. |
2 4 7 7 3 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 9. |
2 4 3 7 7 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 10. |
2 4 3 7 7 1 4 6 3 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 11. |
2 4 3 1 7 7 4 6 3 8 3 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 12. |
2 4 3 1 7 7 4 6 3 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 13. |
2 4 3 1 4 7 7 6 3 8 3 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 14. |
2 4 3 1 4 7 7 6 3 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 15. |
2 4 3 1 4 3 7 6 7 8 3 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 16. |
2 4 3 1 4 3 7 6 7 8 3 9 2 6 7 6 5 i j |
Szukamy |
| 17. |
2 4 3 1 4 3 3 6 7 8 7 9 2 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 18. |
2 4 3 1 4 3 3 6 7 8 7 9 2 6 7 6 5 i j |
Szukamy |
| 19. |
2 4 3 1 4 3 3 2 7 8 7 9 6 6 7 6 5 i j |
Wymieniamy i przesuwamy j. |
| 20. |
2 4 3 1 4 3 3 2 5 8 7 9 6 6 7 6 7 ^ i Lewa partycja j Prawa partycja |
Brak dalszych elementów do wymiany. Piwot wymieniamy z elementem na pozycji j-tej. Podział na partycje zakończony. |
Po zakończeniu podziału na partycje wskaźnik j wyznacza pozycję piwotu. Lewa partycja zawiera elementy mniejsze od piwotu i rozciąga się od początku zbioru do pozycji
| d[ ] | - Zbiór zawierający elementy do posortowania. Zakres indeksów elementów jest dowolny. |
| lewy | - indeks pierwszego elementu w zbiorze, lewy ∈ C |
| prawy | - indeks ostatniego elementu w zbiorze, prawy ∈ C |
| d[ ] | - Zbiór zawierający elementy posortowane rosnąco |
| piwot | - | element podziałowy |
| i, j | - | indeksy, i, j ∈ C |
| K01: |
![]() |
| K02: | piwot ← d[i]; d[i] ← d[prawy]; j ← lewy |
| K03: | Dla i =
lewy, lewy + 1, ..., prawy
- 1: wykonuj kroki K04...K05 |
| K04: | Jeśli d[i] ≥ piwot, to wykonaj kolejny obieg pętli K03 |
| K05: | d[i] ↔ d[j]; j ← j + 1 |
| K06: | d[prawy] ← d[j]; d[j] ← piwot |
| K07: | Jeśli lewy <
j - 1, to Sortuj_szybko(lewy, j - 1) |
| K08: | Jeśli j + 1 <
prawy, to Sortuj_szybko(j + 1, prawy) |
| K09: | Zakończ |
Algorytm sortowania szybkiego wywołujemy podając za lewy indeks pierwszego elementu zbioru, a za prawy indeks elementu ostatniego (czyli Sortuj_szybko(1,n)). Zakres indeksów jest dowolny - dzięki temu ten sam algorytm może również sortować fragment zbioru, co wykorzystujemy przy sortowaniu wyliczonych partycji.

Na element podziałowy wybieramy element leżący w środku dzielonej partycji. Wyliczamy jego pozycję i zapamiętujemy ją tymczasowo w zmiennej i. Robimy to po to, aby dwukrotnie nie wykonywać tych samych rachunków.
Element d[i] zapamiętujemy w zmiennej piwot, a do d[i] zapisujemy ostatni element partycji. Dzięki tej operacji piwot został usunięty ze zbioru.
Ustawiamy zmienną j na początek partycji. Zmienna ta zapamiętuje pozycję podziału partycji.
W pętli sterowanej zmienną i przeglądamy kolejne
elementy od pierwszego do przedostatniego (ostatni został
umieszczony na pozycji piwotu, a piwot zapamiętany). Jeśli i
Po zakończeniu pętli element z pozycji j-tej przenosimy na koniec partycji, aby zwolnić miejsce dla piwotu, po czym wstawiamy tam piwot. Zmienna j wskazuje zatem wynikową pozycję piwotu. Pierwotna partycja została podzielona na dwie partycje:
|
partycja lewa od pozycji
lewy do j
- 1 zawiera elementy mniejsze od piwotu |
Sprawdzamy, czy partycje te obejmują więcej niż jeden element. Jeśli tak, to wywołujemy rekurencyjnie algorytm sortowania szybkiego przekazując mu granice wyznaczonych partycji. Po powrocie z wywołań rekurencyjnych partycja wyjściowa jest posortowana rosnąco. Kończymy algorytm.
C++// Sortowanie Szybkie
//-------------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
int d[N];
// Procedura sortowania szybkiego
//-------------------------------
void Sortuj_szybko(int lewy, int prawy)
{
int i,j,piwot;
i = (lewy + prawy) / 2;
piwot = d[i];
d[i] = d[prawy];
for(j = i = lewy; i < prawy; i++)
if(d[i] < piwot)
{
swap(d[i], d[j]);
j++;
}
d[prawy] = d[j];
d[j] = piwot;
if(lewy < j - 1) Sortuj_szybko(lewy, j - 1);
if(j + 1 < prawy) Sortuj_szybko(j + 1, prawy);
}
// Program główny
//---------------
int main()
{
int i;
srand((unsigned)time(NULL));
cout << " Sortowanie szybkie\n"
"------------------------\n"
" (C)2005 Jerzy Walaszek \n\n"
"Przed sortowaniem:\n\n";
// Najpierw wypełniamy tablicę d[]
// liczbami pseudolosowymi, a następnie
// wyświetlamy jej zawartość
for(i = 0; i < N; i++)
d[i] = rand() % 100;
for(i = 0; i < N; i++)
cout << setw(4) << d[i];
cout << endl << endl;
// Sortujemy
Sortuj_szybko(0,N - 1);
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++)
cout << setw(4) << d[i];
cout << endl << endl;
system("pause");
return 0;
}
|
Pascal// Sortowanie Szybkie
//-------------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
program Quick_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Procedura sortowania szybkiego
//-------------------------------
procedure Sortuj_szybko(lewy, prawy : integer);
var
i,j,piwot,x : integer;
begin
i := (lewy + prawy) div 2;
piwot := d[i];
d[i] := d[prawy];
j := lewy;
for i := lewy to prawy - 1 do
if d[i] < piwot then
begin
x := d[i];
d[i] := d[j];
d[j] := x;
inc(j);
end;
d[prawy] := d[j];
d[j] := piwot;
if lewy < j - 1 then
Sortuj_szybko(lewy, j - 1);
if j + 1 < prawy then
Sortuj_szybko(j + 1, prawy);
end;
// Program główny
//---------------
var
i : integer;
begin
writeln(' Sortowanie szybkie');
writeln('------------------------');
writeln(' (C)2005 Jerzy Walaszek ');
writeln;
// Najpierw wypełniamy tablicę d[]
// liczbami pseudolosowymi, a następnie
// wyświetlamy jej zawartość
randomize;
for i := 1 to N do
d[i] := random(100);
writeln('Przed sortowaniem:');
writeln;
for i := 1 to N do
write(d[i] : 4);
writeln;
writeln;
// Sortujemy
Sortuj_szybko(1,N);
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:');
writeln;
for i := 1 to N do
write(d[i] : 4);
writeln;
writeln;
writeln('Nacisnij Enter...');
readln;
end.
|
Basic' Sortowanie szybkie
'-------------------
' (C)2012 mgr Jerzy Wałaszek
' I Liceum Ogólnokształcące
' w Tarnowie
DECLARE SUB Sortuj_szybko(lewy AS INTEGER,_
prawy AS INTEGER)
CONST N = 20 ' liczebność zbioru
DIM SHARED d(N) AS INTEGER
DIM i AS INTEGER
PRINT " Sortowanie szybkie"
PRINT "-----------------------"
PRINT "(C)2005 Jerzy Walaszek"
PRINT
PRINT "Przed sortowaniem:"
PRINT
' Wypełniamy tablicę liczbami
' pseudolosowymi i wyświetlamy je
RANDOMIZE
FOR i = 1 TO N
d(i) = INT(RND * 100)
PRINT USING "####";d(i);
NEXT
PRINT
PRINT
' Sortujemy
Sortuj_szybko(1,N)
' Wyświetlamy wynik sortowania
PRINT "Po sortowaniu:"
PRINT
FOR i = 1 TO N
PRINT USING "####";d(i);
NEXT
PRINT
PRINT
PRINT "Nacisnij Enter..."
SLEEP
END
' Procedura sortowania szybkiego
'-------------------------------
SUB Sortuj_szybko(lewy AS INTEGER, _
prawy AS INTEGER)
DIM AS INTEGER i, j, piwot
i = (lewy + prawy) \ 2
piwot = d(i)
d(i) = d(prawy)
j = lewy
FOR i = lewy TO prawy - 1
IF d(i) < piwot THEN
SWAP d(i), d(j)
j += 1
END IF
NEXT
d(prawy) = d(j)
d(j) = piwot
IF lewy < j - 1 THEN _
Sortuj_szybko(lewy, j - 1)
IF j + 1 < prawy THEN _
Sortuj_szybko(j + 1, prawy)
END SUB
|
Python
(dodatek)# Sortowanie szybkie
#-------------------
# (C)2012 mgr Jerzy Wałaszek
# I Liceum Ogólnokształcące
# w Tarnowie
import random
n = 20 # liczebność zbioru
d = [random.randrange(100) for i in range(n)]
# Procedura sortowania szybkiego
#-------------------------------
def sortuj_szybko(lewy,prawy):
i = (lewy + prawy) // 2
piwot = d[i]
d[i] = d[prawy]
j = lewy
for i in range(lewy,prawy):
if d[i] < piwot:
d[i],d[j] = d[j],d[i]
j += 1
d[prawy] = d[j]
d[j] = piwot
if lewy < j - 1:
sortuj_szybko(lewy, j - 1)
if j + 1 < prawy:
sortuj_szybko(j + 1, prawy)
# program główny
print(" Sortowanie szybkie")
print("---------------------")
print("(C)2026 Jerzy Wałaszek")
print()
print("Przed sortowaniem:")
print()
for i in range(n):
print("%4d" % (d[i]),end="")
print()
print()
# Sortujemy
sortuj_szybko(0,n - 1)
# Wyświetlamy wynik sortowania
print("Po sortowaniu:")
print()
for i in range(n):
print("%4d" % (d[i]),end="")
print()
print()
input("Naciśnij Enter...")
|
| Wynik: |
Sortowanie szybkie --------------------- (C)2026 Jerzy Wałaszek Przed sortowaniem: 21 54 97 49 62 31 76 58 51 9 34 55 31 46 76 15 75 29 1 13 Po sortowaniu: 1 9 13 15 21 29 31 31 34 46 49 51 54 55 58 62 75 76 76 97 Naciśnij Enter... |
JavaScript<html>
<head>
</head>
<body>
<form style="BORDER-RIGHT: #ff9933 1px outset;
PADDING-RIGHT: 4px; BORDER-TOP: #ff9933 1px outset;
PADDING-LEFT: 4px; PADDING-BOTTOM: 1px;
BORDER-LEFT: #ff9933 1px outset; PADDING-TOP: 1px;
BORDER-BOTTOM: #ff9933 1px outset;
BACKGROUND-COLOR: #ffcc66" name="frmquicksort">
<h3 style="text-align: center">Sortowanie Szybkie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 mgr Jerzy Wałaszek - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Sortuj" name="B1">
</p>
<p id="t_out" style="TEXT-ALIGN: center">...</p>
</form>
<script language=javascript>
// Sortowanie Szybkie
//-------------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
var N = 20; // Liczebność zbioru.
var d = new Array(N)
// Procedura sortowania szybkiego
//-------------------------------
function Sortuj_szybko(lewy, prawy)
{
var i,j,piwot,x;
i = Math.floor((lewy + prawy) / 2);
piwot = d[i]; d[i] = d[prawy];
for(j = i = lewy; i < prawy; i++)
if(d[i] < piwot)
{
x = d[i]; d[i] = d[j]; d[j] = x;
j++;
}
d[prawy] = d[j]; d[j] = piwot;
if(lewy < j - 1) Sortuj_szybko(lewy, j - 1);
if(j + 1 < prawy) Sortuj_szybko(j + 1, prawy);
}
// Program główny
//---------------
function main()
{
var i,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
// a następnie wyświetlamy jej zawartość
for(i = 0; i < N; i++) d[i] = Math.floor(Math.random() * 100);
t = "Przed sortowaniem:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
// Sortujemy
Sortuj_szybko(0, N - 1);
// Wyświetlamy wynik sortowania
t += "<BR><BR>Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t
}
</script>
</body>
</html> |
| Cechy Algorytmu Sortowania Szybkiego | |
| klasa złożoności obliczeniowej optymistyczna | O(n log n) |
| klasa złożoności obliczeniowej typowa | |
| klasa złożoności obliczeniowej pesymistyczna | O(n2) |
| Sortowanie w miejscu | TAK |
| Stabilność | NIE |
Na początku partycji
Na końcu partycji
W miejscu losowym wewnątrz partycji
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.