You are on page 1of 209

Algorytmy Sortujące 2014-10-03

©2008 mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek
Wersja 4.0 - zakończono 19 XI 2005, odwiedzono 203341 razy.
Zoptymalizowane dla IE i Firefox
przy rozdzielczości 1280x1024

Artykuł opisuje podstawowe algorytmy sortowania danych. Algorytmy zostały zaimplementowane w kilku językach programowania (C++, Pascal, Basic,
Python i JavaScript).

Spis treści
Wstęp
Sortowanie zwariowane
Sortowanie głupie
Sortowanie bąbelkowe - wersja 1
Sortowanie bąbelkowe - wersja 2
Sortowanie bąbelkowe - wersja 3
Sortowanie bąbelkowe - wersja 4 - wersja zoptymalizowana
Sortowanie bąbelkowe - wersja 5 - dwukierunkowa
Sortowanie przez wybór
Sortowanie przez wstawianie
Binarne sortowanie przez wstawianie
Sortowanie metodą Shella
Sortowanie przez scalanie
Sortowanie przez kopcowanie - drzewo binarne
Sortowanie przez kopcowanie - tworzenie kopca
Sortowanie przez kopcowanie - rozbiór kopca
Sortowanie przez kopcowanie
Sortowanie szybkie
Sortowanie rozrzutowe
Sortowanie kubełkowe
Sortowanie kubełkowe - listy
Sortowanie kubełkowe - wersja listowa
Sortowanie przez zliczanie
Sortowanie pozycyjne
Podsumowanie

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/index.php 1 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Wstęp
Podrozdziały
Uwagi na temat języków programowania
Porządek w zbiorze
Kryterium uporządkowania zbioru
Czasowa złożoność obliczeniowa
Badania algorytmów sortujących

Sortowanie danych jest jednym z podstawowych problemów programowania komputerów, z którym prędzej czy później spotka się każdy
programista. Poniżej przedstawiamy tylko nieliczne dziedziny, w których występuje potrzeba sortowania danych:

sport - wyniki uzyskane przez poszczególnych zawodników należy ułożyć w określonej kolejności, aby wyłonić zwycięzcę oraz podać
lokatę każdego zawodnika.
bank - spłaty kredytów należy ułożyć w odpowiedniej kolejności, aby wiadomo było kto i kiedy ma płacić odsetki do banku.
grafika - wiele algorytmów graficznych wymaga porządkowania elementów, np. ścian obiektów ze względu na odległość od obserwatora.
Uporządkowanie takie pozwala później określić, które ze ścian są zakrywane przez inne ściany dając w efekcie obraz trójwymiarowy.
bazy danych - informacja przechowywana w bazie danych może wymagać różnego rodzaju uporządkowania, np. lista książek może być
alfabetycznie porządkowana wg autorów lub tytułów, co znacznie ułatwia znalezienie określonej pozycji.

Artykuł ma na celu dokładne zapoznanie uczniów z podstawowymi algorytmami sortującymi, ich własnościami oraz umiejętnym doborem
algorytmów sortujących dla danego zadania. Wbrew obiegowym opiniom nie ma "idealnego" i "uniwersalnego" algorytmu sortującego - jeden
algorytm jest lepszy w jednej sytuacji, drugi w innej. Dlatego dokładna znajomość własności algorytmów sortujących pozwala na tworzenie
naprawdę efektywnych aplikacji.
Z problemem sortowania powiązane są problemy wyszukiwania danych. Dlatego zapraszamy naszych czytelników do zapoznania się z
artykułem o algorytmach wyszukujących.

Uwagi na temat języków programowania


Prezentowane w artykule algorytmy wzbogaciliśmy o proste przykłady programów utworzonych w poniższych środowiskach
programowania::
Dev-Pascal
Code::Blocks (C++)
FreeBasic
JavaScript
Wszystkie są darmowo dostępne poprzez sieć Internet. Programy nie są celem artykułu, lecz jedynie dodatkiem do niego.
Podstawą jest zawsze algorytm, który w artykule zostaje dokładnie omówiony. Dlatego programy dokładnie odzwierciedlają dany
algorytm i nie stosujemy w nich różnych "sztuczek", które mają na celu poprawę efektywności.

Porządek w zbiorze
Zbiór posortowany to taki zbiór, w którym kolejne elementy są poukładane w pewnym porządku (kolejności). Porządek ten
możemy określić za pomocą relacji ≥ lub ≤ (albo dowolnej innej relacji porządkowej, która jednoznacznie wyznacza kolejność
elementów w zbiorze). Równość jest konieczna w przypadku, gdy elementy zbioru mogą przyjmować takie same wartości. Na
przykład zbiór liczb:
D = { 1, 3, 3, 5, 7, 7, 8, 9 }
jest posortowany rosnąco, ponieważ pomiędzy każdymi dwoma kolejnymi elementami zachodzi relacja:
element poprzedni jest mniejszy lub równy od elementu następnego
Odwrotnie, zbiór:
D = { 9, 8, 6, 6, 4, 2, 1, 1, 0 }
jest posortowany malejąco, ponieważ pomiędzy każdymi dwoma kolejnymi elementami zachodzi relacja:
element poprzedni jest większy lub równy od elementu następnego.
Oczywiście zbiór wcale nie musi składać się z liczb (chociaż tak naprawdę każdy rodzaj danych komputerowych w końcu
sprowadza się do liczb, gdyż wewnętrznie jest reprezentowany przez kody binarne). W takim przypadku należy określić dla
każdego elementu tzw. klucz (ang. key), wg którego dokonywane jest sortowanie. Ponieważ klucz jest liczbą, zatem obowiązują
dla niego podane wyżej zasady kolejności elementów. Na przykład dla tekstów kluczem mogą być kody poszczególnych znaków.
Większość języków programowania posiada operatory porównywania ciągu znaków (problemem może być sortowanie wg zasad
języka polskiego - nie wystarczy wtedy porównywać kodów znakowych, ponieważ kody polskich literek ą, ć, Ć itd. są zwykle
większe od kodów liter alfabetu łacińskiego, ale i ten problem daje się z powodzeniem rozwiązać przez odpowiedni dobór kluczy).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 2 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

Przez sortowanie będziemy rozumieć taką zmianę kolejności elementów zbioru nieuporządkowanego (permutację), aby w wyniku
spełniały one założony porządek.

Czasowa złożoność obliczeniowa


Kolejnym zagadnieniem, które powinniśmy omówić we wstępie, jest tzw. czasowa złożoność obliczeniowa (ang. computational
complexity) algorytmu sortującego (istnieje również złożoność pamięciowa). Określa ona statystycznie czas wykonywania
algorytmu w zależności od liczby danych wejściowych. Czasowa złożoność obliczeniowa wyrażana jest liczbą tzw. operacji
dominujących, czyli takich, które mają bezpośredni wpływ na czas wykonywania algorytmu. Dzięki takiemu podejściu
uniezależniamy czasową złożoność obliczeniową od szybkości komputera, na którym dany algorytm jest realizowany. Złożoność
obliczeniową charakteryzujemy przy pomocy tzw. notacji O (omikron). Oto odpowiednie przykłady:

O(n) - Algorytm o liniowej zależności czasu wykonania od ilości danych. Dwukrotny wzrost liczby
przetwarzanych danych powoduje dwukrotny wzrost czasu wykonania. Tego typu złożoność
powstaje, gdy dla każdego elementu należy wykonać stałą liczbę operacji.
O(n2) - Algorytm, w którym czas wykonania rośnie z kwadratem liczby przetwarzanych elementów.
Dwukrotny wzrost liczby danych powoduje czterokrotny wzrost czasu wykonania. Tego typu
złożoność powstaje, gdy dla każdego elementu należy wykonać ilość operacji proporcjonalną do
liczby wszystkich elementów.
O(n log n) - Dobre algorytmy sortujące mają taką właśnie złożoność obliczeniową. Czas wykonania przyrasta
dużo wolniej od wzrostu kwadratowego. Tego typu złożoność powstaje, gdy zadanie dla n
elementów można rozłożyć na dwa zadania zawierające po połowie elementów.
O(n!) - Bardzo pesymistyczne algorytmy, czas wykonania rośnie szybko ze wzrostem liczby elementów
wejściowych, czyli znalezienie rozwiązania może zająć najszybszym komputerom całe wieki lub
O(an) tysiąclecia. Takich algorytmów należy unikać jak ognia !

Zapis O( ) określamy mianem klasy złożoności obliczeniowej algorytmu. Klasa czasowej złożoności obliczeniowej umożliwia
porównywanie wydajności różnych algorytmów sortujących. Z reguły proste algorytmy posiadają wysoką złożoność obliczeniową -
długo dochodzą do wyniku końcowego. Algorytmy bardziej skomplikowane posiadają mniejszą złożoność obliczeniową - szybko
dochodzą do rozwiązania. Złożoność obliczeniowa wszystkich algorytmów sortujących została dokładnie oszacowana - my
również dokonujemy tego w niniejszym opracowaniu.

Przykład:
Załóżmy, iż mamy program sortujący dane zbudowany na bazie algorytmu sortującego o klasie złożoności
obliczeniowej O(n2). Sto elementów jest sortowane w czasie 1 sekundy. Ile czasu zajmie posortowanie za pomocą
tego programu zbioru o tysiącu elementach? Odpowiedź brzmi - 100 sekund. Ponieważ ilość danych wzrosła 10
razy, to czas obliczeń wzrósł 102, czyli 100 razy. Poniżej przedstawiamy odpowiednią tabelkę.

Lp. n Czas obliczeń


1. 100 = 1 sekunda
2. 1.000 = 100 sekund = 1 minuta 40 sekund
3. 10.000 = 10.000 sekund = 2 godziny 46 minut 40 sekund
4. 100.000 = 1.000.000 sekund = 11 dni 13 godzin 46 minut 40 sekund
5. 1.000.000 = 100.000.000 sekund = 3 lata 2 miesiące 9 godzin 46 minut 40 sekund
6. 10.000.000 = 1 x 1010 sekund = 317 lat 1 miesiąc 4 dni 17 godzin 46 minut 40 sekund

Widzimy więc, iż algorytm ten spisuje się dobrze tylko przy niewielkiej liczbie elementów. Gdy liczba sortowanych elementów jest
duża, czas oczekiwania na rozwiązanie może być nie do zaakceptowania. Dlatego właśnie informatycy poświęcili tak dużo
swojego wysiłku na opracowanie odpowiednio szybkich algorytmów sortujących (te najszybsze mają klasę złożoności O(n log n)
).
Oprócz złożoności czasowej rozważa się również złożoność pamięciową. Określa ona ilość zasobów komputera, których
wymaga dany algorytm w zależności od liczby danych wejściowych. Tutaj także ma zastosowanie notacja omikron. Przy
określaniu złożoności algorytmu należy wziąć pod uwagę oba typy złożoności obliczeniowej.
Ze względu na złożoność pamięciową algorytmy sortujące dzielimy na dwie podstawowe grupy:

Algorytmy sortujące w miejscu (ang. in place) - wymagają stałej liczby dodatkowych struktur danych, która nie zależy od
liczby elementów sortowanego zbioru danych (ani od ich wartości). Dodatkowa złożoność pamięciowa jest zatem klasy
O(1). Sortowanie odbywa się wewnątrz zbioru. Ma to bardzo istotne znaczenie w przypadku dużych zbiorów danych, gdyż
mogłoby się okazać, iż posortowanie ich nie jest możliwe z uwagi na brak pamięci w systemie. Większość opisanych tu
algorytmów sortuje w miejscu, co jest ich bardzo dużą zaletą.
Algorytmy nie sortujące w miejscu - wymagają zarezerwowania w pamięci dodatkowych obszarów, których wielkość jest
uzależniona od liczby sortowanych elementów lub od ich wartości. Tego typu algorytmy są zwykle bardzo szybkie w
działaniu, jednakże okupione to jest dodatkowymi wymaganiami na pamięć. Zatem w pewnych sytuacjach może się
okazać, iż taki algorytm nie będzie w stanie posortować dużego zbioru danych, ponieważ system komputerowy nie posiada
wystarczającej ilości pamięci RAM.
Algorytmy sortujące dzieli się również na dwie grupy:

Algorytmy stabilne - zachowują kolejność elementów równych. Oznacza to, iż elementy o tych samych wartościach będą
występowały w tej samej kolejności w zbiorze posortowanym, co w zbiorze nieposortowanym. Czasami ma to znaczenie,
gdy sortujemy rekordy bazy danych i nie chcemy, aby rekordy o tym samym kluczu zmieniały względem siebie położenie.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 3 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

Algorytmy niestabilne - kolejność wynikowa elementów równych jest nieokreślona (zwykle nie zostaje zachowana).

Badania algorytmów sortowania


W opracowaniu zbadamy prezentowane algorytmy sortujące pod kątem czasu sortowania. Otrzymane wyniki pozwolą nam
wyciągnąć różne ciekawe wnioski oraz porównać efektywność opisywanych algorytmów przy sortowaniu tych samych zbiorów.
Każdy algorytm (z wyjątkiem Bogo Sort, co stanie się oczywiste dla każdego, kto się z nim zapozna) będzie sortował kolejno DLA
GENIUSZA
identyczne zbiory o liczebności 1000, 2000, 4000, 8000, 16000 elementów (dla algorytmów szybkich zmierzymy jeszcze czasy
sortowań zbiorów zawierające 32000, 64000 i 128000 elementów). Elementy zbioru będą liczbami rzeczywistymi.
W danej turze sortowania wyznaczymy następujące czasy:

tpo - czas sortowania zbioru posortowanego. Nie, to nie jest pomyłka. Pomiar tego czasu da nam odpowiedź, czy
algorytm wykorzystuje fakt posortowania zbioru.
tod - czas sortowania zbioru uporządkowanego odwrotnie. To zwykle jest ciężki orzech do zgryzienia dla
algorytmów, które w typowych warunkach radzą sobie całkiem sprawnie. Tego typu sytuacja występuje przy
zmianie kierunku uporządkowania zbioru, który wcześniej został już posortowany.
tpp - czas sortowania zbioru uporządkowanego, w którym pierwszy element przyjmuje wartość losową.
Wykonamy dziesięć sortowań dla każdego zbioru uśredniając wynik. Tego typu sytuacja występuje przy
dodawaniu nowego elementu na początku zbioru już uporządkowanego.
tpk czas posortowania zbioru uporządkowanego, w którym ostatni element przyjmuje wartość losową.
-
Wykonamy dziesięć sortowań uśredniając wynik. Tego typu sytuacja występuje przy dodawaniu nowego
elementu na końcu zbioru uporządkowanego.
tnp - czas posortowania zbioru z losowym rozkładem elementów. Wykonamy dziesięć sortowań uśredniając
wynik. Ten czas poinformuje nas, jak dany algorytm radzi sobie w typowych warunkach.

Poniżej przedstawiamy program, który będzie stosowany do badań. Zastosowane w nim rozwiązania mogą się przydać również
przy pomiarze czasu działania innych algorytmów.
Do pomiaru czasu wykorzystujemy dwie funkcje biblioteki Win32API operujące na tzw. sprzętowym liczniku wydajności. Licznik
ten zlicza takty procesora i jest 64-bitowy. Jeśli komputer nie posiada takiego licznika, to funkcje zwracają wartość logiczną false.
QueryPerformanceFrequency(adres zmiennej 64-bitowej) - funkcja umieszcza w podanej zmiennej całkowitej 64-
bitowej ilość taktów procesora na 1 sekundę.
QueryPerformanceCounter(adres zmiennej 64-bitowej) - funkcja umieszcza w podanej zmiennej całkowitej 64-bitowej
stan licznika taktów procesora.

Zasada pomiaru czasu jest następująca:

DevPascal
...
uses Windows;
var
qpf : int64; // ilość taktów procesora na sekundę
qpc1,qpc2 : int64; // stany liczników 64-bitowych
tqpc : int64; // czas operacji odczytu czasu
t : extended; // czas w sekundach
...
if QueryPerformanceFrequency(addr(qpf)) then
begin
// kalibrujemy czas operacji pomiaru czasu
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
...
// wykonujemy pomiar czasu
QueryPerformanceCounter(addr(qpc1));
// tutaj jest kod, którego czas pracy mierzymy
QueryPerformanceCounter(addr(qpc2));
t := (qpc2 - qpc1 - tqpc) / qpf; // czas w sekundach
...
end
else
writeln('Na tym komputerze program testowy nie pracuje...');
...

DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 4 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Tutaj podajemy nazwe algorytmu';
K1 = '----------------------------------------';
K2 = '(C)2005 mgr J.Walaszek I LO w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 5 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Bardzo duże znaczenie dla otrzymanych wyników ma środowisko, w którym program testowy będzie pracował. Aby usunąć obce
wpływy mogące zakłócić wyniki, komputer pracuje w czystym systemie Windows XP z SP2 bez uruchomionych w tle procesów, z
wyłączoną siecią oraz z wyłączonym oprogramowaniem antywirusowym. Parametry są następujące:

Środowisko pracy programu testującego


Element Stan
Procesor Intel Pentium Celeron 1,7GHz
RAM 512MB
System Windows XP Professional SP 2
Sieć Wyłączona
Inne programy Wyłączone

Wynikiem działania programu będą odpowiednie czasy sortowania zbiorów, które zależą od użytego do doświadczeń sprzętu
komputerowego - na twoim komputerze na pewno uzyskasz inne czasy. Co zatem będziemy badać?
Otóż dla każdego czasu określimy klasę czasowej złożoności obliczeniowej. Wg definicji (podanej w artykule o liczbach
pierwszych) klasa czasowej złożoności obliczeniowej jest funkcją liczby elementów przetwarzanych przez algorytm o jak
najprostszej postaci, do której jest proporcjonalny czas wykonania algorytmu (nie jest to definicja formalna!!!).

Przykład:
Jeśli pewien algorytm posiada czasową złożoność obliczeniową klasy O(n2), to czas wykonania algorytmu dla n
elementów jest w przybliżeniu proporcjonalny do kwadratu n, czyli:

t(n) ≈ cn2
n - liczba przetwarzanych elementów
t(n) - czas przetwarzania n-elementów w algorytmie
c - stała proporcjonalności pomiędzy t(n) a n2

Jeśli podzielimy otrzymane czasy działania algorytmu przez n2, to otrzymamy:

t(n)
≈c
n2

Co z tego wynika? To proste - jeśli dany algorytm ma rzeczywiście klasę złożoności obliczeniowej O(n2), to otrzymany iloraz jest
w przybliżeniu taki sam dla wszystkich zmierzonych czasów. Wartość liczbowa stałej c jest dla nas zupełnie nieistotna (zależy
ona od parametrów komputera, na którym uruchomiliśmy nasz program testowy). Ważne jest jedynie, aby dla kolejnych ilorazów
miała ona taką samą wartość (z pewnym przybliżeniem, co jest chyba oczywiste).
Aby zatem określić klasę złożoności obliczeniowej, otrzymane w wyniku wykonania programu testowego czasy będziemy kolejno
dzielić przez: n, n2, n3 i n·logn, Do tego celu wykorzystamy prosty arkusz kalkulacyjny:

mnożnik: 1,00E+03 1,00E+06 1,00E+12 1,00E+04


Lp n t(n) O(n)? O(n2)? O(n3)? O(nlogn)?
1 1000 1,057523 1,06 1,06 1057,52 1,06

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 6 / 209
Algorytmy Sortujące - Wstęp 2014-10-03

2 2000 4,117282 2,06 1,03 514,66 1,88


3 4000 15,921192 3,98 1,00 248,77 3,33
4 8000 61,238923 7,65 0,96 119,61 5,90
5 16000 258,838272 16,18 1,01 63,19 11,58
6 32000 1032,526252 32,27 1,01 31,51 21,56
7 64000 4120,517722 64,38 1,01 15,72 40,33
8 128000 16452,586878 128,54 1,00 7,85 75,76
Średnio: 32,014 1,009 257,353 20,175
(Kliknij tutaj, aby pobrać plik arkusza Excel.)

Najpierw w kolumnie t(n) umieszczamy otrzymane czasy sortowania dla poszczególnych wartości n. W przykładzie kolumna
zawiera już dane oznakowane kolorem fioletowym. Podane czasy arkusz podzieli w kolejnych kolumnach przez wielkości n, n2, n3
i nlogn pobrane z kolumny n. Ponieważ wyniki są zwykle bardzo małe, a nas interesuje nie ich wartość liczbowa tylko to, czy są
stałe w pewnych granicach, czy też nie, arkusz wymnaża ilorazy przez podane u góry kolumny mnożniki tak dobrane, aby wyniki
w kolumnie były dobrze czytelne (najlepiej większe od 1). Teraz wystarczy sprawdzić, w której kolumnie wyliczone ilorazy
przyjmują w przybliżeniu stałą wartość. W przykładzie jest to kolumna O(n2). Zatem algorytm wykazuje klasę czasowej
złożoności obliczeniowej O(n2).
Drugą badaną dziedziną będzie efektywność opisywanych algorytmów. Ponieważ wszystkie z nich posortują identyczne zbiory
danych i wykonają się w tych samych warunkach oraz na tym samym sprzęcie komputerowym, to otrzymane czasy pozwolą nam
zorientować się, który z algorytmów robi to najlepiej i policzyć względny wzrost prędkości działania:

Przykład:
Jeśli algorytm A1 sortuje dany plik w czasie t1 = 32 [s] a algorytm A2 wykonuje to samo zadanie w czasie
t2 = 24 [s], to względny wzrost prędkości algorytmu A2 w stosunku do A1 wyraża się wzorem:

Wynika z tego, iż algorytm A2 jest w tym konkretnym przypadku 11/4 razy szybszy w stosunku do algorytmu A1.
Na końcu artykułu przeprowadzimy podsumowanie otrzymanych wyników i wyciągniemy z nich odpowiednie wnioski.
Zapraszam do lektury
mgr Jerzy Wałaszek

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0001.php 7 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie zwariowane
Bogo Sort, Bozo Sort, Blort Sort
Podrozdziały
Algorytm Programy
Szczegóły implementacyjne algorytmu Program w języku Pascal
Specyfikacja problemu Program w języku C++
Lista kroków Program w języku Basic
Schemat blokowy Program w języku JavaScript
Podsumowanie

Algorytm
Pierwszy z prezentowanych algorytmów sortujących opiera się na dosyć zwariowanych zasadach. Jego
działanie możemy scharakteryzować na przykładzie układania talii kart. Bierzemy talię kart. Sprawdzamy,
czy jest ułożona. Jeśli nie, tasujemy ją i znów sprawdzamy ułożenie. Operacje sprawdzania i tasowania
wykonujemy dotąd, aż talia nam się ułoży w pożądanej kolejności kart.
Nic nie sortujemy, wręcz dokonujemy operacji odwrotnej - tasowania, a talia może zostać posortowana.
Dlaczego? Wynika to z praw rachunku prawdopodobieństwa. Otóż tasowanie powoduje, iż karty przyjmują
losowe permutacje swoich położeń. Ponieważ każda permutacja zbioru kart jest równie prawdopodobna (jeśli
przy tasowaniu nie oszukujemy), zatem możemy też otrzymać układ uporządkowany. Oczywiście wynik taki
pojawia się dosyć rzadko (bądźmy szczerzy - przy dużej liczbie elementów bardzo, bardzo... rzadko). Nie
polecamy sortowania tą metodą zbiorów liczniejszych niż 9 elementów.
Algorytm opiera się na losowym sortowaniu zbioru. Tymczasem w komputerze nie mamy tak naprawdę
dostępu do liczb czysto losowych. Zadowalamy się ich przybliżeniem, czyli liczbami pseudolosowymi powstającymi na bazie
algorytmicznej (dokładny opis tworzenia liczb pseudolosowych znajdziesz w artykule o liczbach pierwszych). Może się zatem
zdarzyć, iż nasz generator pseudolosowy nigdy nie wygeneruje potrzebnej sekwencji liczb pseudolosowych, zatem algorytm
sortujący nie będzie w stanie ukończyć swojej pracy.
Z tego powodu jest to jeden z najgorszych algorytmów sortujących. Posiada pesymistyczną czasową złożoność obliczeniową
klasy O(n •n!). Złożoność taką nazywamy złożonością super wykładniczą. Co gorsze, ten sam zbiór raz może zostać
błyskawicznie posortowany (gdy akurat mamy szczęście), a innym razem możemy czekać na wynik nawet cały rok (albo jeszcze
dłużej). Sortowanie odbywa się w miejscu.

Szczegóły implementacji
Jeśli za pomocą podanego algorytmu chcemy posortować zbiór liczbowy (a takimi się zajmujemy w opracowaniu), to musimy
rozwiązać dwa istotne problemy: sprawdzenie posortowania elementów oraz losowe potasowanie.

Sprawdzenie posortowania elementów


Aby upewnić się, iż zbiór jest posortowany, należy porównać ze sobą wszystkie kolejne sąsiednie elementy. Jeśli spełniają
założoną kolejność, to zbiór jest uporządkowany. Jeśli chociaż jedna para elementów zbioru jest w złej kolejności ze względu na
przyjęty porządek, to zbiór nie jest uporządkowany.

Losowe potasowanie elementów zbioru


Operacja ta ma na celu pomieszanie elementów w zbiorze, aby przyjęły przypadkowe pozycje. Najprościej dokonamy tego, losując
dwa numery elementów, a następnie zamieniając wylosowane elementy miejscami. Jeśli operację taką powtórzymy wystarczającą
liczbę razy (np. 3-krotną liczbę elementów w zbiorze), to zawartość zbioru zostanie potasowana (wymieszana).
Podstawową operacją jest zamiana zawartości dwóch elementów zbioru. Wymaga ona
trzech kroków oraz zmiennej pomocniczej do tymczasowego przechowania jednego z
elementów.
W pierwszym kroku przenosimy do zmiennej pomocniczej jeden z elementów. W drugim
kroku na zwolnione miejsce wstawiamy drugi z elementów, a na koniec w kroku trzecim na
miejsce drugiego elementu przenosimy element zapamiętany w zmiennej pomocniczej.
Obok prezentujemy w formie graficznej tę prostą zasadę.

Pascal x := a; a := b; b := x;

C++ i JavaScript x = a; a = b; b = x;

Operację zamiany zawartości dwóch elementów w algorytmach przedstawianych w

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 8 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

postaci listy kroków będziemy oznaczali symbolem: ↔


Kolejna operacja to losowanie indeksu elementu. Wykorzystamy tutaj generator liczb
pseudolosowych. Wygenerowany indeks powinien być liczbą pseudolosową z
zakresu od 1 do n (w C++ i JavaScript obowiązuje zakres od 0 do n-1), gdzie n
oznacza ilość elementów w zbiorze. Operację tę wykonujemy następująco:

Pascal indeks := 1 + random(n);

C++ indeks = rand() % n;

JavaScript indeks = Math.floor(Math.random() * n);

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - zmienna sterująca pętli, i Î N
i1, i2 - losowe indeksy elementów zbioru d[ ], i1, i2 Î N

Lista kroków
Algorytm procedury Tasuj
K01: Dla i = 1,2,...,3 × n, wykonuj K02...K03
K02: Wylosuj indeksy i1, i2 Î <1,n>
K03: d[i1] ↔ d[i2]
K04: Zakończ

Algorytm funkcji Posortowane


K01: Dla i = 1,2,...,n - 1, jeśli d[i] > d[i + 1], to Posortowane ← false i zakończ
K02: Posortowane ← true
K03: Zakończ

Algorytm główny BogoSort


K01: Dopóki Posortowane = false: Tasuj
K02: Zakończ

Schemat blokowy
Trzon algorytmu stanowi pojedyncza pętla warunkowa typu while. Na początku wywołana zostaje funkcja
sprawdzająca posortowanie zbioru - Posortowane?. Jeśli da wynik pozytywny, kończymy algorytm.
Przy wyniku negatywnym wywołujemy procedurę tasowania elementów zbioru - Tasuj i pętla jest
powtarzana aż do skutku (który może nigdy nie nastąpić z powodu niedoskonałości generacji liczb
pseudolosowych! - zobacz na uwagi umieszczone na początku rozdziału).

Algorytm funkcji Posortowane? zbudowany jest z pojedynczej pętli iteracyjnej


sterowanej zmienną licznikową i. Zmienna i pełni rolę indeksu kolejno
porównywanych elementów sortowanego zbioru. Sprawdzamy, czy zbiór jest
posortowany rosnąco (dla porządku malejącego należy zamienić w teście
kolejności elementów zbioru relację większości na relację mniejszości).
Wykonanie pętli rozpoczynamy od pierwszego elementu i kontynuujemy do
przedostatniego (tzn. o numerze n - 1). Element i-ty oraz (i + 1)-wszy porównujemy
ze sobą. Jeśli relacja jest spełniona, to elementy te są w złej kolejności (większy
jest przed mniejszym). W takim przypadku wiemy natychmiast, iż zbiór jest
nieposortowany. Przerywamy zatem wykonywanie pętli iteracyjnej, zwracamy jako
wynik działania funkcji wartość logiczną false i kończymy algorytm.
Jeśli relacja w teście nie będzie spełniona, zwiększamy o 1 indeks i rozpoczynamy następny obieg pętli.
Jeśli pętla wykona się do końca, to znaczy, iż wszystkie elementy zbioru są w dobrym porządku. Jako wynik funkcji zwracamy
wartość logiczną true i kończymy algorytm.

Uwaga:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 9 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

Sprawdź, jak zachowa się ten sam algorytm dla zbioru pustego (tzn. przy n = 0) oraz dla zbioru
jednoelementowego (tzn. n = 1). Jakie wyciągniesz stąd wnioski?

Tasowanie elementów zbioru jest operacją odwrotną do ich sortowania. Tutaj celem będzie losowe
ustawienie elementów.
Trzonem algorytmu jest pętla iteracyjna wykonująca się 3n razy. Ilość wykonań można dobrać
doświadczalnie - my przyjęliśmy trzykrotną ilość elementów w tasowanym zbiorze.
Pojedyncza operacja tasowania polega na wylosowaniu dwóch indeksów w zakresie od 1 do n, a
następnie zamianie zawartości elementów zbioru o tych indeksach. W wyniku elementy zbioru
zostaną rozmieszczone losowo.
Zapamiętaj ten algorytm - bardzo przydaje się on w różnych grach losowych, gdzie należy coś
pomieszać (na przykład wszelkie gry karciane).

Uwaga:
Sprawdź co się stanie, gdy wylosowane zostaną dwa takie same indeksy. Czy
musimy się tego obawiać przy tasowaniu zbioru?

Programy
Efekt uruchomienia programu
Sortowanie zwariowane
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
2043 6751 8525 2306 3923 7457 9686 5862
Po sortowaniu:
2043 2306 3923 5862 6751 7457 8525 9686

DevPascal
// Sortowanie Zwariowane
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Bogo_Sort;
const N = 8; // Liczebność zbioru. Nie wstawiaj liczb
// większych od 9, bo możesz się nie
// doczekać rozwiązania
var
d : array[1..N] of integer;
// Funkcja sprawdzająca uporządkowanie w zbiorze
//-----------------------------------------------------
function Posortowane : boolean;
var
i : integer;
begin
for i := 1 to N - 1 do
if d[i] > d[i+1] then
begin
Posortowane := false; Exit;
end;
Posortowane := true;
end;
// Procedura tasująca zbiór
//-------------------------
procedure Tasuj;
var
i,i1,i2,x : integer;
begin
for i := 1 to 3 * N do
begin
i1 := 1 + random(N); i2 := 1 + random(N);
x := d[i1]; d[i1] := d[i2]; d[i2] := x;
end;
end;
// Program główny
//---------------
var
i : integer;
begin
writeln('Sortowanie zwariowane');

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 10 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

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(10000);
writeln('Przed sortowaniem:'); writeln;
for i := 1 to N do write(d[i] : 6);
writeln; writeln;
// Sortujemy
while not Posortowane do Tasuj;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 6);
writeln; writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Zwariowane
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 8; // Liczebność zbioru. Nie wstawiaj liczb
// większych od 9, bo możesz się nie
// doczekać rozwiązania
int d[N];
// Funkcja sprawdzająca uporządkowanie w zbiorze
//-----------------------------------------------------
bool Posortowane()
{
int i;
for(i = 0; i < N - 1; i++) if(d[i] > d[i+1]) return false;
return true;
}
// Procedura tasująca zbiór
//-------------------------
void Tasuj()
{
int i,i1,i2;
for(i = 1; i <= 3 * N; i++)
{
i1 = rand() % N; i2 = rand() % N;
swap(d[i1], d[i2]);
}
}
//******************************************************
int main()
{
int i;
cout << "Sortowanie zwariowane\n"
"----------------------\n"
"(C)2005 Jerzy Walaszek\n\n";
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
// a następnie wyświetlamy jej zawartość
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 10000;
cout << "Przed sortowaniem:\n\n";
for(i = 0; i < N; i++) cout << setw(6) << d[i];
cout << endl << endl;
// Sortujemy
while(!Posortowane()) Tasuj();
// Wyświetlamy wynik sortowania

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 11 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

cout << "Po sortowaniu:\n\n";


for(i = 0; i < N; i++) cout << setw(6) << d[i];
cout << endl << endl;
return 0;
}

Free Basic
' Sortowanie Zwariowane
' --------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 8 ' Liczebność zbioru. Nie wstawiaj liczb
' większych od 9, bo możesz się nie
' doczekać rozwiązania
Dim Shared d(1 To N) As Integer
Declare Function Posortowane() As Integer
Declare Sub Tasuj()
' Program główny
' --------------
Dim i As Integer
Print "Sortowanie zwariowane"
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 10000): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "######"; d(i);: Next
Print
Print
' Sortujemy
While Posortowane() = 0: Tasuj(): Wend
' 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
' Funkcja sprawdzająca uporządkowanie w zbiorze
'-----------------------------------------------------
Public Function Posortowane() As Integer
Dim i As Integer
For i = 1 To N - 1
If d(i) > d(i+1) Then
Posortowane = 0: Exit Function
End If
Next
Posortowane = 1
End Function
' Procedura tasująca zbiór
'-------------------------
Public Sub Tasuj()
Dim i As Integer, i1 As Integer, i2 As Integer
For i = 1 To 3 * N
i1 = 1 + Int(Rnd * N)
i2 = 1 + Int(Rnd * N)
Swap d(i1), d(i2)
Next
End Sub

JavaScript

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 12 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

<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="frmbogosort">
<h3 style="text-align: center">Sortowanie Zwariowane</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Zwariowane
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 8; // Liczebność zbioru. Nie wstawiaj liczb
// większych od 9, bo możesz się nie
// doczekać rozwiązania
var d = Array(N);
// Funkcja sprawdzająca uporządkowanie w zbiorze
//-----------------------------------------------------
function Posortowane()
{
var i;
for(i = 0; i < N - 1; i++) if(d[i] > d[i+1]) return false;
return true;
}
// Procedura tasująca zbiór
//-------------------------
function Tasuj()
{
var i,i1,i2,x;
for(i = 1; i <= 3 * N; i++)
{
i1 = Math.floor(Math.random() * N); i2 = Math.floor(Math.random() * N);
x = d[i1]; d[i1] = d[i2]; d[i2] = x;
}
}
//******************************************************
function main()
{
var i,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
for(i = 0; i < N; i++) d[i] = Math.floor(Math.random() * 10000);
t = "Przed sortowaniem:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
t += "<BR><BR>";
// Sortujemy
while(!Posortowane()) Tasuj();
// Wyświetlamy wynik sortowania
t += "Po sortowaniu<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Zwariowane
(C)2012 I LO w Tarnowie - I LO w Tarnowie

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 13 / 209
Algorytmy Sortujące - Sortowanie Zwariowane 2014-10-03

Sortuj
...

Podsumowanie
Zaprezentowany algorytm jest ekstremalnie złym algorytmem sortującym i na pewno nikt o zdrowych zmysłach nie będzie go
stosował. Jednakże zawiera dwa ciekawe składniki, które można wykorzystywać w "poważniejszych" projektach
programistycznych: sprawdzanie posortowania zbioru oraz tasowanie elementów zbioru.
Algorytmu Bogo Sort nie testujemy w naszym programie badania czasów sortowania, ponieważ, jak zdążyliście się zorientować,
nawet posortowanie 10 elementów może zająć całkiem sporą chwilę czasu. W ramach eksperymentu próbowałem posortować tym
algorytmem zbiór 12 liczb, lecz muszę szczerze przyznać, iż po dwóch godzinach czekania zniecierpliwiony zakończyłem
program w sposób awaryjny. Posortowanie 1000 liczb wydaje się niewykonalne w tym miliardoleciu.
Jako ciekawostkę podam fakt, iż informatycy terminem "bogo sort" określają program lub algorytm, którego idea działania jest tak
beznadziejnie głupia, iż praktycznie nie może dać rozwiązania w sensownym czasie. Zatem jeśli usłyszysz zdanie: "twój program
to bogo sort", to już będziesz wiedział o co chodzi rozmówcy... :)
Cechy Algorytmu Sortowania Zwariowanego
klasa złożoności obliczeniowej O(n × n!)
Sortowanie w miejscu TAK
Stabilność NIE

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0002.php 14 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Głupie sortowanie bąbelkowe


Stupid Bubble Sort
Podrozdziały
Algorytm Programy Badanie algorytmów sortujących
Specyfikacja problemu Program w języku Pascal Podsumowanie
Lista kroków Program w języku C++ Zadania dla ambitnych
Schemat blokowy Program w języku Basic
Program w języku JavaScript

Algorytm
Sortowanie głupie jest również bardzo złym algorytmem sortującym, lecz, w przeciwieństwie do
opisanego w poprzednim rozdziale sortowania zwariowanego, daje zawsze poprawne wyniki. Zasada
działania jest bardzo prosta:
Przeglądamy kolejne pary sąsiednich elementów sortowanego zbioru. Jeśli bieżąco przeglądana
para elementów jest w złej kolejności, elementy pary zamieniamy miejscami i całą operację
rozpoczynamy od początku zbioru. Jeśli przeglądniemy wszystkie pary, zbiór będzie posortowany.
Naiwność (lub, jak wolą niektórzy, głupota) algorytmu wyraża się tym, iż po napotkaniu
nieposortowanych elementów algorytm zamienia je miejscami, a następnie rozpoczyna całą pracę
od początku zbioru. Złożoność obliczeniowa algorytmu przy sortowaniu zbioru nieuporządkowanego
ma klasę O(n3). Sortowanie odbywa się w miejscu.
Algorytm sortowania głupiego występuje w dwóch wersjach - rekurencyjnej oraz iteracyjnej. Wersja
rekurencyjna jest jeszcze gorsza od iteracyjnej, gdyż dodatkowo zajmuje pamięć na kolejne poziomy wywołań rekurencyjnych,
dlatego nie będziemy się nią zajmować (zainteresowanych odsyłam do Wikipedii).

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - zmienna sterująca pętli, i Î N

Lista kroków
K01: Dla i = 1,2,...,n - 1: wykonuj K02...K04
K02: Jeśli d[i] ≤ d[i + 1], to wykonaj następny obieg K01
K03: d[i] ↔ d[i + 1]
K04: Idź do K01
K05: Zakończ

Schemat blokowy
Rozpoczynamy przeglądanie zbioru od pierwszego elementu - indeks i przyjmuje wartość 1. W
pętli sprawdzamy kolejność elementu d[i] z elementem następnym d[i+1]. Ponieważ założyliśmy
porządek rosnący, to w przypadku d[i] > d[i+1] elementy te są w złej kolejności (dla porządku
malejącego należy zmienić relację większości na relację mniejszości). W takiej sytuacji
zamieniamy miejscami elementy, indeks i ustawiamy z powrotem na 1 (powrót na sam początek
algorytmu byłby nieco kłopotliwy do zrealizowania w językach programowania, stąd dla prostoty
ustawiamy i na 1 za operacją zamiany elementów) i wracamy na początek pętli.
Jeśli porównywane elementy są w dobrej kolejności, zwiększamy indeks i o 1, sprawdzamy, czy
osiągnął już wartość końcową n i, jeśli nie, wracamy na początek pętli. W przeciwnym razie
kończymy - zbiór jest posortowany.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 15 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

Programy
Efekt uruchomienia programu
Sortowanie glupie
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
60 70 46 52 97 34 14 60 4 56 77 34 75 72 78 86 45 12 30 99
Po sortowaniu:
4 12 14 30 34 34 45 46 52 56 60 60 70 72 75 77 78 86 97 99

DevPascal
// Sortowanie Głupie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Stupid_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,x : integer;
begin
writeln(' Sortowanie glupie ');
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;
// Sortujemy
i := 1;
repeat
if d[i] > d[i+1] then // Porządek rosnący
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
i := 1;
continue;
end;
inc(i);
until i = N;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Głupie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 16 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

// Program główny
//---------------
int main()
{
int d[N],i;
cout << " Sortowanie glupie\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
i = 0;
do
{
if(d[i] > d[i+1]) // Porządek rosnący
{
swap(d[i], d[i+1]);
i = 0;
continue;
}
i++;
} while(i < N-1);
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Głupie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer, i As Integer
Print " Sortowanie glupie "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
i = 1
Do
If d(i) > d(i+1) Then ' Porządek rosnący
Swap d(i), d(i+1)
i = 1
Continue Do
End If
i = i + 1
Loop Until i = N
' Wyświetlamy wynik sortowania
Print "Po sortowaniu"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter...";
Sleep
End

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 17 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

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="frmstupidsort">
<h3 style="text-align: center">Sortowanie Głupie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Głupie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
i = 0;
do
{
if(d[i] > d[i+1]) // Porządek rosnący
{
x = d[i]; d[i] = d[i+1]; d[i+1] = x;
i = 0;
continue;
}
i++;
} while(i < N-1);
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Głupie
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badanie algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania głupiego w środowisku opisanym we wstępie. Jednakże,
ze względu na bardzo długi czas sortowania zbiorów o dużej liczbie elementów, ograniczyliśmy się jedynie do 8000 elementów.
Program testujący jest następujący: DLA
GENIUSZA

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 18 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie Glupie - Stupid Sort';
K1 = '----------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 4; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
D : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
i := 1;
repeat
if d[i] > d[i+1] then // Porządek rosnący
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
i := 1;
continue;
end;
inc(i);
until i = n;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 19 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika - najlepiej na noc):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie Glupie - Stupid Sort


----------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000006 1.087045 0.001226 0.002302 0.676225
2000 0.000012 7.998662 0.005473 0.010103 5.377530
4000 0.000024 64.041837 0.020801 0.030448 43.222395
8000 0.000050 513.938879 0.043996 0.087417 343.565348
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania głupiego
wyciągamy następujące wnioski

Cechy Algorytmu Sortowania Głupiego


klasa złożoności obliczeniowej optymistyczna O(n) - O(n2)

klasa złożoności obliczeniowej typowa O(n3)


klasa złożoności obliczeniowej pesymistyczna O(n3)
Sortowanie w miejscu TAK

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 20 / 209
Algorytmy Sortujące - Sortowanie Głupie 2014-10-03

Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n) O(n3) O(n2) O(n2) O(n3)
Sortowanie głupie
tpo << tod tpp ≈1tpk tnp ≈2tod
2 3
1. Dla zbioru już posortowanego klasa czasowej złożoności obliczeniowej wynosi O(n) - liniowa. Czas sortowania jest
pomijalnie mały.
2. Dla zbioru posortowanego odwrotnie klasa czasowej złożoności obliczeniowej wynosi O(n3) - sześcienna, a czas
sortowania jest najdłuższy z otrzymanych, jest to zatem przypadek najbardziej niekorzystny.
3. Dla zbioru posortowanego z losowym elementem na początku klasa czasowej złożoności obliczeniowej wynosi O(n2) -
kwadratowa. Czas sortowania jest bardzo mały w porównaniu z czasem sortowania zbioru nieuporządkowanego.
4. Dla zbioru posortowanego z losowym elementem na końcu klasa czasowej złożoności obliczeniowej wynosi O(n2) -
kwadratowa.
5. Dla zbioru o losowym rozkładzie elementów klasa czasowej złożoności obliczeniowej wynosi O(n3) - sześcienna. Czas
sortowania jest krótszy w porównaniu z czasem sortowania zbioru uporządkowanego odwrotnie.

Zadania dla ambitnych


1. Z uwagi na bardzo długi czas pracy programu testującego musieliśmy ograniczyć do 8000 elementów badanie czasów sortowania dla
algorytmu sortowania głupiego. Na podstawie wyników oszacuj przybliżone czasy dla 16000, 32000, 64000 oraz 128000 elementów
(zadanie możesz rozwiązać pisząc odpowiedni program lub wykorzystując do obliczeń arkusz kalkulacyjny). Jak długo musiałby
pracować nasz program testowy, aby zebrać wszystkie te wyniki? Wykorzystaj informację o ilości sortowań każdego typu wykonywanych
w programie testującym.
2. Dlaczego czas tpo ma liniową czasową złożoność obliczeniową?
3. Uzasadnij, iż dla czasów tpp i tpk algorytm wykazuje kwadratową złożoność obliczeniową.

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0003.php 21 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie bąbelkowe - wersja nr 1


Bubble Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja 2
Specyfikacja problemu Program w języku Pascal Podsumowanie Wersja 3
Lista kroków Program w języku C++ Zadania dla ambitnych Wersja 4
Schemat blokowy Program w języku Basic Dwukierunkowe sortowanie bąbelkowe
Program w języku JavaScript

Algorytm
Algorytm sortowania bąbelkowego jest jednym z najstarszych algorytmów sortujących. Można
go potraktować jako ulepszenie opisanego w poprzednim rozdziale algorytmu sortowania głupiego.
Zasada działania opiera się na cyklicznym porównywaniu par sąsiadujących elementów i zamianie
ich kolejności w przypadku niespełnienia kryterium porządkowego zbioru. Operację tę wykonujemy
dotąd, aż cały zbiór zostanie posortowany.
Algorytm sortowania bąbelkowego przy porządkowaniu zbioru nieposortowanego ma klasę czasowej
złożoności obliczeniowej równą O(n2). Sortowanie odbywa się w miejscu.

Przykład:
Jako przykład działania algorytmu sortowania bąbelkowego posortujemy przy jego pomocy 5-cio elementowy zbiór
liczb {5 4 3 2 1}, który wstępnie jest posortowany w kierunku odwrotnym, co możemy uznać za przypadek
najbardziej niekorzystny, ponieważ wymaga przestawienia wszystkich elementów.
Obieg Zbiór Opis operacji
5 4 3 2 1 Rozpoczynamy od pierwszej pary, która wymaga wymiany elementów
4 5 3 2 1 Druga para też wymaga zamiany elementów

1 4 3 5 2 1 Wymagana wymiana elementów


4 3 2 5 1 Ostatnia para również wymaga wymiany elementów

4 3 2 1 5 Stan po pierwszym obiegu. Zwróć uwagę, iż najstarszy element (5) znalazł się na końcu
zbioru, a najmłodszy (1) przesunął się o jedną pozycję w lewo.
4 3 2 1 5 Para wymaga wymiany
3 4 2 1 5 Para wymaga wymiany
3 2 4 1 5 Para wymaga wymiany
2 3 2 1 4 5 Elementy są w dobrej kolejności, zamiana nie jest konieczna.
Stan po drugim obiegu. Zwróć uwagę, iż najmniejszy element (1) znów przesunął się o
3 2 1 4 5 jedną pozycję w lewo. Z obserwacji tych można wywnioskować, iż po każdym obiegu
najmniejszy element wędruje o jedną pozycję ku początkowi zbioru. Najstarszy element
zajmuje natomiast swe miejsce końcowe.
3 2 1 4 5 Para wymaga wymiany
2 3 1 4 5 Para wymaga wymiany

3 2 1 3 4 5 Dobra kolejność
2 1 3 4 5 Dobra kolejność

2 1 3 4 5 Stan po trzecim obiegu. Wnioski te same.

2 1 3 4 5 Para wymaga wymiany


1 2 3 4 5 Dobra kolejność

4 1 2 3 4 5 Dobra kolejność
1 2 3 4 5 Dobra kolejność

1 2 3 4 5 Zbiór jest posortowany. Koniec

Posortowanie naszego zbioru wymaga 4 obiegów. Jest to oczywiste: w przypadku najbardziej niekorzystnym

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 22 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

najmniejszy element znajduje się na samym końcu zbioru wejściowego. Każdy obieg przesuwa go o jedną pozycję w
kierunku początku zbioru. Takich przesunięć należy wykonać n - 1 (n - ilość elementów w zbiorze).
Algorytm sortowania bąbelkowego, w przeciwieństwie do algorytmu sortowania głupiego, nie przerywa porównywania
par elementów po napotkaniu pary nie spełniającej założonego porządku. Po zamianie kolejności elementów
sprawdzana jest kolejna para elementów sortowanego zbioru. Dzięki temu podejściu rośnie efektywność algorytmu
oraz zmienia się klasa czasowej złożoności obliczeniowej z O(n3) na O(n2).

Uwaga:
Algorytm sortowania bąbelkowego jest uważany za bardzo zły algorytm sortujący. Można go
stosować tylko dla niewielkiej liczby elementów w sortowanym zbiorze (do około 5000). Przy
większych zbiorach czas sortowania może być zbyt długi.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.
Zmienne pomocnicze
i, j - zmienne sterujące pętli, i, j Î N

Lista kroków
K01: Dla j = 1,2,...,n - 1: wykonuj K02
K02: Dla i = 1,2,...,n - 1: jeśli d[i] > d[i + 1], to d[i] ↔ d[i + 1]
K03: Zakończ

Schemat blokowy
Sortowanie wykonywane jest w dwóch zagnieżdżonych pętlach. Pętla zewnętrzna nr 1
kontrolowana jest przez zmienną j. Wykonuje się ona n - 1 razy. Wewnątrz pętli nr 1 umieszczona
jest pętla nr 2 sterowana przez zmienną i. Wykonuje się również n - 1 razy. W efekcie algorytm
wykonuje w sumie:
T1(n) = (n - 1)2 = n2 - 2n + 1
obiegów pętli wewnętrznej, po których zakończeniu zbiór zostanie posortowany.
Sortowanie odbywa się wewnątrz pętli nr 2. Kolejno porównywany jest i-ty element z elementem
następnym. Jeśli elementy te są w złej kolejności, to zostają zamienione miejscami. W tym
miejscu jest najważniejsza różnica pomiędzy algorytmem sortowania bąbelkowego a algorytmem
sortowania głupiego. Ten drugi w momencie napotkania elementów o złej kolejności zamienia je
miejscami i rozpoczyna cały proces sortowania od początku. Algorytm sortowania bąbelkowego
wymienia miejscami źle ułożone elementy sortowanego zbioru i przechodzi do następnej pary
zwiększając indeks i o 1. Dzięki takiemu podejściu rośnie efektywność, co odzwierciedla klasa
czasowej złożoności obliczeniowej:

Sortowanie głupie - O(n3); Sortowanie bąbelkowe - O(n2)

Programy
Efekt uruchomienia programu
Sortowanie babelkowe
WERSJA NR 1
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
74 77 21 76 64 19 43 47 75 77 66 47 60 7 97 71 87 95 76 79
Po sortowaniu:
7 19 21 43 47 47 60 64 66 71 74 75 76 76 77 77 79 87 95 97

DevPascal
// Sortowanie Bąbelkowe - Wersja nr 1
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 23 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Bubble_Sort_1;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,j,x : integer;
begin
writeln(' Sortowanie babelkowe ');
writeln(' WERSJA NR 1 ');
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;
// Sortujemy
for j := 1 to N - 1 do
for i := 1 to N - 1 do
if d[i] > d[i+1] then // Porządek rosnący
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Bąbelkowe - Wersja nr 1
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j;
cout << " Sortowanie babelkowe\n"
" WERSJA NR 1\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
for(j = 0; j < N - 1; j++)
for(i = 0; i < N - 1; i++)
if(d[i] > d[i + 1]) swap(d[i], d[i + 1]);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 24 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

// Wyświetlamy wynik sortowania


cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Bąbelkowe - Wersja nr 1
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer, i As Integer, j As Integer
Print " Sortowanie babelkowe "
Print " WERSJA NR 1 "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = 1 To N - 1
For i = 1 To N - 1
If d(i) > d(i+1) Then Swap d(i), d(i+1)
Next
Next
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmbubblesort">
<h3 style="text-align: center">Sortowanie Bąbelkowe - wersja nr 1</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Bąbelkowe - wersja nr 1
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 25 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

var i,j,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = 0; j < N - 1; j++)
for(i = 0; i < N - 1; i++)
if(d[i] > d[i + 1])
{
x = d[i]; d[i] = d[i + 1]; d[i + 1] = x;
};
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Bąbelkowe - wersja nr 1


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania bąbelkowego 1 w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie bąbelkowe - Bubble Sort 1';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 5; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
for j := 1 to n - 1 do
for i := 1 to n - 1 do
if d[i] > d[i+1] then // Porządek rosnący
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 26 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 27 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie bąbelkowe - Bubble Sort 1


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.007080 0.033954 0.008131 0.009170 0.021347
2000 0.025329 0.145372 0.025706 0.027021 0.086866
4000 0.096382 0.541764 0.102081 0.102371 0.347644
8000 0.414819 2.194081 0.418721 0.414379 1.401096
16000 1.672559 8.789338 1.679220 1.675513 5.628816
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów

(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)


(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania bąbelkowego 1
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Bąbelkowego


wersja nr 1
klasa złożoności obliczeniowej optymistyczna O(n2)
klasa złożoności obliczeniowej typowa O(n2)
klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:


optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp

O(n2) O(n2) O(n2) O(n2) O(n2)


Sortowanie bąbelkowe
wersja nr 1 tpo ≈ 1tod tpo= tpp= tpk tnp ≈ 2tod
5 3
1. Wszystkie badane przez nas czasy sortowania są proporcjonalne do kwadratu liczby elementów zbioru. Klasa czasowej
złożoności obliczeniowej wynosi O(n2).
2. Czasy sortowania tpo, tpp oraz tpk są praktycznie takie same.
3. Czas sortowania zbioru nieuporządkowanego jest krótszy od czasu sortowania zbioru uporządkowanego odwrotnie.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

Sortowanie głupie 1 n 1 1 n
Sortowanie bąbelkowe 1 n 33 6 4 33
źle dobrze źle źle dobrze

4. Porównując wzrost prędkości algorytmu sortowania bąbelkowego w stosunku do algorytmu sortowania głupiego
zauważamy, iż korzyść następuje w przypadku sortowania zbioru uporządkowanego odwrotnie oraz zbioru
nieuporządkowanego. Wzrost prędkości jest proporcjonalny liniowo do liczby elementów w sortowanym zbiorze. W
pozostałych przypadkach algorytm sortowania głupiego jest dużo szybszy od tej wersji algorytmu.

Zadania dla ambitnych


http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 28 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

1. Uzasadnij, iż wszystkie czasy dla tej wersji algorytmu są proporcjonalne do kwadratu liczby sortowanych elementów.
2. Dlaczego czasy tpo, tpp oraz tpk są takie same?
3. Uzasadnij wyniki otrzymane przy badaniu wzrostu prędkości algorytmu sortowania bąbelkowego w stosunku do algorytmu sortowania
głupiego.

Zobacz również na: Wersję 2 | Wersję 3 | Wersję 4 | Dwukierunkowe sortowanie bąbelkowe

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0004.php 29 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie bąbelkowe - wersja nr 2


Bubble Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja 1
Specyfikacja problemu Program w języku Pascal Podsumowanie Wersja 3
Lista kroków Program w języku C++ Zadania dla ambitnych Wersja 4
Schemat blokowy Program w języku Basic Dwukierunkowe sortowanie bąbelkowe
Program w języku JavaScript

Algorytm
Podany w poprzednim rozdziale algorytm sortowania bąbelkowego można zoptymalizować pod
względem czasu wykonania. Jeśli przyjrzymy się dokładnie obiegom wykonywanym w tym
algorytmie, to zauważymy bardzo istotną rzecz:

Po wykonaniu pełnego obiegu w algorytmie sortowania bąbelkowego


najstarszy element wyznaczony przez przyjęty porządek zostaje
umieszczony na swoim właściwym miejscu - na końcu zbioru.

Wniosek ten jest oczywisty. W każdej kolejnej parze porównywanych elementów element starszy
przechodzi na drugą pozycję. W kolejnej parze jest on na pierwszej pozycji, a skoro jest
najstarszym, to po porównaniu znów przejdzie na pozycję drugą itd. - jest jakby ciągnięty na koniec zbioru (jak bąbelek powietrza
wypływający na powierzchnię wody).

Przykład:
Wykonamy jeden obieg sortujący dla zbioru pięcioelementowego
{ 9 3 1 7 0 }. Elementem najstarszym jest pierwszy element - liczba 9.

Obieg Zbiór Opis operacji


9 3 1 7 0 Para wymaga przestawienia elementów. Element najstarszy przejdzie na drugą pozycję w parze.
3 9 1 7 0 Konieczne przestawienie elementów. Element najstarszy znów trafi na pozycję drugą w parze.
1 3 1 9 7 0 Konieczne przestawienie elementów.
3 1 7 9 0 Ostatnia para również wymaga przestawienia elementów.
3 1 7 0 9 Koniec obiegu. Najstarszy element znalazł się na końcu zbioru.

Co z tego wynika dla nas? Otóż po każdym obiegu na końcu zbioru tworzy się podzbiór uporządkowanych
najstarszych elementów. Zatem w kolejnych obiegach możemy pomijać sprawdzanie ostatnich elementów -
liczebność zbioru do posortowania z każdym obiegiem maleje o 1.

Przykład:
Dokończmy sortowania podanego powyżej zbioru uwzględniając podane przez nas fakty. Po pierwszym obiegu na
końcu zbioru mamy umieszczony element najstarszy. W drugim obiegu będziemy zatem sortować zbiór 4
elementowy, w trzecim obiegu 3 elementowy i w obiegu ostatnim, czwartym - zbiór 2 elementowy.

Obieg Zbiór Opis operacji


3 1 7 0 9 Para wymaga przestawienia elementów.
1 3 7 0 9 Dobra kolejność
2
1 3 7 0 9 Konieczne przestawienie elementów.
1 3 0 7 9 Koniec obiegu. Na końcu zbioru mamy 2 elementy uporządkowane.
1 3 0 7 9 Dobra kolejność
3 1 3 0 7 9 Konieczne przestawienie elementów.
1 0 3 7 9 Koniec obiegu. Na końcu zbioru mamy 3 elementy uporządkowane.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 30 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

1 0 3 7 9 Konieczne przestawienie elementów.


4
0 1 3 7 9 Koniec ostatniego obiegu - zbiór jest posortowany.

W porównaniu do tabelki z poprzedniego rozdziału nawet wzrokowo możemy zauważyć istotne zmniejszenie ilości niezbędnych
operacji.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i, j - zmienne sterujące pętli, i, j Î N

Lista kroków
K01: Dla j = n - 1, n - 2, ..., 1: wykonuj K02
K02: Dla i = 1, 2, ..., j: jeśli d[i] > d[i + 1], to d[i] ↔ d[i + 1]
K03: Zakończ

Schemat blokowy
Zmiany w stosunku do poprzedniej wersji zaznaczyliśmy na schemacie blokowym innym kolorem
elementów. Są one następujące:
- pętla zewnętrzna nr 1 zlicza obiegi wstecz, tzn. pierwszy obieg ma numer n-1. Dzięki takiemu
podejściu w zmiennej j mamy zawsze numer ostatniego elementu, do którego ma dojść pętla
wewnętrzna nr 2. Ta zmiana wymaga również odwrotnej iteracji zmiennej j.
- pętla wewnętrzna sprawdza w warunku kontynuacji, czy wykonała j obiegów, a nie jak
poprzednio n-1 obiegów. Dzięki temu po każdym obiegu pętli nr 1 (zewnętrznej) pętla nr 2 będzie
wykonywać o jeden obieg mniej.
Pozostała część algorytmu nie jest zmieniona - w pętli wewnętrznej nr 2 sprawdzamy, czy
element d[i] jest w złej kolejności z elementem d[i+1]. Sprawdzany warunek spowoduje
posortowanie zbioru rosnąco. Przy sortowaniu malejącym zmieniamy relację większości na relację
mniejszości. Jeśli warunek jest spełniony, zamieniamy miejscami element d[i] z elementem
d[i+1], po czym kontynuujemy pętlę nr 2 zwiększając o 1 indeks i. Po każdym zakończeniu pętli
nr 2 indeks j jest zmniejszany o 1.
Ilość obiegów pętli wewnętrznej wynosi:

T2(n) = (n-1) + (n-2) + ... + 2 + 1 =n(n - 1) =1(n2 - n)


2 2

Otrzymane wyrażenie ma wciąż kwadratową klasę złożoności obliczeniowej, jednakże T2(n) < T1(n) dla n > 1. Osiągnęliśmy
zatem większą efektywność działania dzięki wprowadzonym zmianom.

Programy
Efekt uruchomienia programu
Sortowanie babelkowe
WERSJA NR 2
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
44 29 43 80 95 88 40 45 28 13 8 90 49 28 76 64 22 70 4 6
Po sortowaniu:
4 6 8 13 22 28 28 29 40 43 44 45 49 64 70 76 80 88 90 95

DevPascal
// Sortowanie Bąbelkowe - Wersja nr 2
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 31 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

//--------------------------------------------------------
program Bubble_Sort_2;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,j,x : integer;
begin
writeln(' Sortowanie babelkowe ');
writeln(' WERSJA NR 2 ');
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;
// Sortujemy
for j := N - 1 downto 1 do
for i := 1 to j do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Bąbelkowe - Wersja nr 2
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j;
cout << " Sortowanie babelkowe\n"
" WERSJA NR 2\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
for(j = N - 1; j > 0; j--)
for(i = 0; i < j; i++)
if(d[i] > d[i + 1]) swap(d[i], d[i + 1]);
// Wyświetlamy wynik sortowania

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 32 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

cout << "Po sortowaniu:\n\n";


for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Bąbelkowe - Wersja nr 2
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer, i As Integer, j As Integer
Print " Sortowanie babelkowe "
Print " WERSJA NR 2 "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = N - 1 To 1 Step -1
For i = 1 To j
If d(i) > d(i+1) Then Swap d(i), d(i+1)
Next
Next
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmbubblesort">
<h3 style="text-align: center">Sortowanie Bąbelkowe - wersja nr 2</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Bąbelkowe - wersja nr 2
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,x,t;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 33 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi


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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = N - 1; j > 0; j--)
for(i = 0; i < j; i++)
if(d[i] > d[i + 1])
{
x = d[i]; d[i] = d[i + 1]; d[i + 1] = x;
};
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Bąbelkowe - wersja nr 2


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania bąbelkowego 2 w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie bąbelkowe - Bubble Sort 2';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 5; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
for j := n - 1 downto 1 do
for i := 1 to j do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 34 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 35 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program


Nazwa: Sortowanie bąbelkowe - Bubble Sort 2
--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.003118 0.030915 0.003249 0.003674 0.019875
2000 0.012156 0.124258 0.013537 0.014906 0.074068
4000 0.052770 0.499130 0.049157 0.048772 0.296212
8000 0.194066 1.995982 0.196131 0.196660 1.191403
16000 0.775087 7.993864 0.800502 0.786996 4.756371
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania bąbelkowego 2
wyciągamy następujące wnioski:
Cechy Algorytmu Sortowania Bąbelkowego
wersja nr 2
klasa złożoności obliczeniowej optymistyczna O(n2)

klasa złożoności obliczeniowej typowa O(n2)


klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp

O(n2) O(n2) O(n2) O(n2) O(n2)


Sortowanie bąbelkowe
wersja nr 2
tpo ≈ 1 tod tpo=tpp=tpk tnp ≈ 3tod
10 5
1. Wszystkie czasy sortowania są proporcjonalne do kwadratu liczby elementów w sortowanych zbiorach, zatem klasa
czasowej złożoności obliczeniowej jest równa O(n2).
2. Czasy sortowania tpo, tpp oraz tpk są praktycznie takie same.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

Sortowanie bąbelkowe 1 13 11 7
≈ ≈ ≈2 ≈2 ≈
Sortowanie bąbelkowe 2
6 10 6
dobrze niewiele dobrze dobrze niewiele

3. Analizując wzrost prędkości algorytmu sortowania bąbelkowego w wersji 2 w stosunku do wersji 1 zauważamy, iż
wprowadzona zmiana faktycznie zwiększyła ogólną prędkość działania. Jednakże korzyść w typowym przypadku zbioru
nieuporządkowanego jest stosunkowo niewielka. Największy wzrost prędkości notujemy przy sortowaniu zbiorów częściowo
uporządkowanych.

Zadania dla ambitnych


1. Jakiego typu operacje są wykonywane w algorytmie sortowania bąbelkowego?
2. Na jakich operacjach zyskaliśmy w tej wersji algorytmu?
3. Które operacje dominują przy wyznaczaniu czasów tpo, tpp oraz tpk ?

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 36 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

4. Uzasadnij wyniki otrzymane przy badaniu wzrostu prędkości algorytmu sortowania bąbelkowego w wersji 2 w stosunku do wersji 1.
5. Dokonaj analogicznego porównania wzrostu prędkości tego algorytmu w stosunku do algorytmu sortowania głupiego.

Zobacz również na: Wersję 1 | Wersję 3 | Wersję 4 | Dwukierunkowe sortowanie bąbelkowe

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0005.php 37 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie bąbelkowe - wersja nr 3


Bubble Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja 1
Specyfikacja problemu Program w języku Pascal Podsumowanie Wersja 2
Lista kroków Program w języku C++ Zadania dla ambitnych Wersja 4
Schemat blokowy Program w języku Basic Dwukierunkowe sortowanie bąbelkowe
Program w języku JavaScript

Algorytm
Algorytm sortowania bąbelkowego wykonuje dwa rodzaje operacji:
- test bez zamiany miejsc elementów
- test ze zamianą miejsc elementów.
Pierwsza z tych operacji nie sortuje zbioru, jest więc operacją pustą. Druga operacja
dokonuje faktycznej zmiany porządku elementów, jest zatem operacją sortującą.
Ze względu na przyjęty sposób sortowania algorytm bąbelkowy zawsze musi wykonać tyle
samo operacji sortujących. Tego nie możemy zmienić. Jednakże możemy wpłynąć na
eliminację operacji pustych. W ten sposób usprawnimy działanie algorytmu.
Jeśli dokładnie przyjrzałeś się wersjom 1 i 2, które prezentowaliśmy w poprzednich
rozdziałach, to powinieneś dokonać następujących spostrzeżeń:
1. Wersja pierwsza jest najmniej optymalną wersją algorytmu bąbelkowego. Wykonywane są wszystkie możliwe operacje
sortujące i puste.
2. Wersja druga redukuje ilość operacji pustych poprzez ograniczanie liczby obiegów pętli wewnętrznej (sortującej).

Możliwa jest dalsza redukcja operacji pustych, jeśli będziemy sprawdzać, czy w pętli wewnętrznej były przestawiane elementy
(czyli czy wykonano operacje sortujące). Jeśli nie, to zbiór jest już posortowany (dlaczego?) i możemy zakończyć pracę
algorytmu.
Teraz rośnie trudność wyznaczenia czasowej złożoności obliczeniowej, ponieważ ilość faktycznie wykonywanych operacji
porównań i przestawień zależy od rozkładu elementów w sortowanym zbiorze. Zadanie komplikuje dodatkowo fakt, iż operacja
pusta jest zwykle wykonywana kilkakrotnie szybciej od operacji sortującej. Na pewno można powiedzieć, iż dla zbioru
posortowanego algorytm wykona tylko n - 1 operacji pustych, zatem w przypadku najbardziej optymistycznym czasowa złożoność
obliczeniowa redukuje się do klasy O(n) - liniowej. W przypadku najbardziej niekorzystnym algorytm wykona wszystkie operacje
puste i sortujące, zatem będzie posiadał klasę czasowej złożoności obliczeniowej O(n2).

Przykład:
Posortujmy zbiór { 3 1 0 7 9 } zgodnie z wprowadzoną modyfikacją.

Obieg Zbiór Opis operacji


3 1 0 7 9 Konieczne przestawienie elementów
1 3 0 7 9 Konieczne przestawienie elementów
1 1 0 3 7 9 Elementy w dobrej kolejności
1 0 3 7 9 Elementy w dobrej kolejności
1 0 3 7 9 Koniec pierwszego obiegu. Ponieważ były przestawienia elementów, sortowanie kontynuujemy
1 0 3 7 9 Konieczne przestawienie elementów
0 1 3 7 9 Elementy w dobrej kolejności
2
0 1 3 7 9 Elementy w dobrej kolejności
0 1 3 7 9 Koniec drugiego obiegu. Było przestawienie elementów, zatem sortowanie kontynuujemy
0 1 3 7 9 Elementy w dobrej kolejności

3 0 1 3 7 9 Elementy w dobrej kolejności

0 1 3 7 9 Koniec trzeciego obiegu. Nie było przestawień elementów, kończymy sortowanie. Wykonaliśmy o 1 obieg
sortujący mniej.

Specyfikacja problemu

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 38 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.
Zmienne pomocnicze
i, j - zmienne sterujące pętli, i, j Î N
p - znacznik zamiany miejsc elementów w zbiorze. p Î N

Lista kroków
K01: Dla j = n - 1, n - 2, ..., 1: wykonuj K02...K04
K02: p←1
K03: Dla i = 1, 2, ..., j: jeśli d[i] > d[i + 1], to d[i] ↔ d[i + 1]; p ← 0
K04: Jeśli p = 1, to zakończ
K05: Zakończ

Schemat blokowy
Wprowadzona do algorytmu sortowania bąbelkowego modyfikacja ma na celu
wykrycie posortowania zbioru. Zmiany zaznaczyliśmy blokami o odmiennym
kolorze.
Zbiór będzie posortowany, jeśli po wykonaniu wewnętrznego obiegu sortującego nie
wystąpi ani jedno przestawienie elementów porządkowanego zbioru.
Przed wejściem do pętli sortującej nr 2 ustawiamy zmienną pomocniczą p. Jeśli w
pętli zajdzie potrzeba przestawienia elementów, to zmienna p jest zerowana. Po
wykonaniu pętli sortującej sprawdzamy, czy zmienna p jest ustawiona. Jeśli tak, to
przestawienie elementów nie wystąpiło, zatem kończymy algorytm. W przeciwnym
razie wykonujemy kolejny obieg pętli nr 1.

Uwaga techniczna:
Zmienna p powinna być typu liczbowego integer, a nie boolean
(chociaż tak może wydawać się właściwiej). Jednakże musimy
pamiętać, iż procesory Pentium są zoptymalizowane na liczby
32-bitowe. Standardowy typ boolean (w C++ bool) jest daną
8-bitową, która wydłuża wykonanie programu, ponieważ dostęp do
takich danych zajmuje procesorowi Pentium o wiele więcej czasu
niż dostęp do danych 32-bitowych.

Programy
Efekt uruchomienia programu
Sortowanie babelkowe
WERSJA NR 3
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
31 17 26 0 42 61 24 89 56 72 92 66 91 13 74 88 10 90 68 25
Po sortowaniu:
0 10 13 17 24 25 26 31 42 56 61 66 68 72 74 88 89 90 91 92

DevPascal
// Sortowanie Bąbelkowe - Wersja nr 3
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Bubble_Sort_3;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 39 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

var
i,j,p,x : integer;
begin
writeln(' Sortowanie babelkowe ');
writeln(' WERSJA NR 3 ');
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;
// Sortujemy
for j := N - 1 downto 1 do
begin
p := 1;
for i := 1 to j do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := 0;
end;
if p = 1 then break;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Bąbelkowe - Wersja nr 3
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j,p;
cout << " Sortowanie babelkowe\n"
" WERSJA NR 3\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
for(j = N - 1; j > 0; j--)
{
p = 1;
for(i = 0; i < j; i++)
if(d[i] > d[i + 1])
{
swap(d[i], d[i + 1]);
p = 0;
}
if(p) break;
}

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 40 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

// Wyświetlamy wynik sortowania


cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Bąbelkowe - Wersja nr 3
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer, i As Integer, j As Integer, p As Integer
Print " Sortowanie babelkowe "
Print " WERSJA NR 3 "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = N - 1 To 1 Step -1
p = 1
For i = 1 To j
If d(i) > d(i+1) Then
Swap d(i), d(i+1)
p = 0
End If
Next
If p = 1 Then Exit For
Next
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmbubblesort">
<h3 style="text-align: center">Sortowanie Bąbelkowe - wersja nr 3</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Bąbelkowe - wersja nr 3
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 41 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

var N = 20; // Liczebność zbioru.


function main()
{
var d = new Array(N);
var i,j,p,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = N - 1; j > 0; j--)
{
p = 1;
for(i = 0; i < j; i++)
if(d[i] > d[i + 1])
{
x = d[i]; d[i] = d[i + 1]; d[i + 1] = x;
p = 0;
}
if(p) break;
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Bąbelkowe - wersja nr 3


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania bąbelkowego 3 w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie bąbelkowe - Bubble Sort 3';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 6; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j,p : integer;
x : real;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 42 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

begin
QueryPerformanceCounter(addr(qpc1));
for j := n - 1 downto 1 do
begin
p := 1;
for i := 1 to j do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := 0;
end;
if p = 1 then break;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 43 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie bąbelkowe - Bubble Sort 3


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000008 0.030413 0.000042 0.002527 0.020769
2000 0.000014 0.122591 0.000084 0.010772 0.072822
4000 0.000025 0.487696 0.000164 0.032994 0.292399
8000 0.000050 1.954120 0.000253 0.095668 1.181462
16000 0.000119 7.963850 0.000707 0.539036 4.686158
32000 0.000283 31.464163 0.001363 1.871901 18.937897
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów

(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)


(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania bąbelkowego 3
wyciągamy następujące wnioski:
Cechy Algorytmu Sortowania Bąbelkowego
wersja nr 3
klasa złożoności obliczeniowej optymistyczna O(n) -O(n2)

klasa złożoności obliczeniowej typowa O(n2)


klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n) O(n2) O(n) O(n2) O(n2)
Sortowanie bąbelkowe
wersja nr 3
tpo << tod tpp << tpk tnp ≈ 3tod
5
1. Wprowadzona zmiana wpłynęła na zmianę klasy czasowej złożoności obliczeniowej przy sortowaniu zbioru
uporządkowanego oraz przy sortowaniu zbioru uporządkowanego z losowym elementem na początku. W obu przypadkach
notujemy proporcjonalność czasu sortowania do liczby elementów w zbiorze, zatem klasa czasowej złożoności
obliczeniowej wynosi O(n).
2. Nie zmieniła się natomiast klasa czasowej złożoności obliczeniowej przy sortowaniu zbioru uporządkowanego odwrotnie,
przy sortowaniu zbioru uporządkowanego z losowym elementem na końcu oraz przy sortowaniu zbioru
nieuporządkowanego. Dlatego w przypadku ogólnym klasa czasowej złożoności obliczeniowej wynosi O(n2).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 44 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe 2014-10-03

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
2
Sortowanie bąbelkowe 2 ≈ n ≈ 1 ≈ 0,07n ≈
3
≈1
5 2
Sortowanie bąbelkowe 3
dobrze brak dobrze dobrze brak

3. Analizując wzrost prędkości algorytmu sortowania bąbelkowego w wersji 3 w stosunku do wersji 2 zauważamy, iż
wprowadzona zmiana nie zwiększyła prędkości działania algorytmu dla przypadku zbioru posortowanego odwrotnie oraz dla
zbioru nieuporządkowanego. Największy zysk (zmniejszenie klasy czasowej złożoności obliczeniowej) występuje przy
sortowaniu zbiorów częściowo uporządkowanych.

Zadania dla ambitnych


1. Uzasadnij zmianę klasy czasowej złożoności obliczeniowej z O(n2) dla operacji sortowania zbioru uporządkowanego w wersjach nr 1 i 2
algorytmu sortowania bąbelkowego na klasę O(n) w wersji nr 3.
2. Dlaczego nie uzyskaliśmy istotnego wzrostu prędkości pracy algorytmu dla przypadku zbioru posortowanego odwrotnie oraz zbioru
nieuporządkowanego.
3. Zbadaj wzrost prędkości algorytmu sortowania bąbelkowego w wersji nr 3 w stosunku do wersji nr 2. Wyciągnij odpowiednie wnioski.

Zobacz również na: Wersję 1 | Wersję 2 | Wersję 4 | Dwukierunkowe sortowanie bąbelkowe

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0006.php 45 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie bąbelkowe - wersja nr 4


Bubble Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja 1
Specyfikacja problemu Program w języku Pascal Podsumowanie Wersja 2
Lista kroków Program w języku C++ Zadania dla ambitnych Wersja 3
Schemat blokowy Program w języku Basic Dwukierunkowe sortowanie bąbelkowe
Program w języku JavaScript

Algorytm
Czy algorytm sortowania bąbelkowego można jeszcze ulepszyć? Tak,
ale zaczynamy już osiągać kres jego możliwości, ponieważ ulepszenia
polegają jedynie na redukcji operacji pustych. Wykorzystamy informację
o miejscu wystąpienia zamiany elementów (czyli o miejscu wykonania
operacji sortującej).
Jeśli w obiegu sortującym wystąpi pierwsza zamiana na pozycji i-tej, to
w kolejnym obiegu będziemy rozpoczynali sortowanie od pozycji o jeden
mniejszej (chyba że pozycja i-ta była pierwszą pozycją w zbiorze).
Dlaczego? Odpowiedź jest prosta. Zamiana spowodowała, iż młodszy
element znalazł się na pozycji i-tej. Ponieważ w obiegu sortującym
młodszy element zawsze przesuwa się o 1 pozycję w kierunku początku
zbioru, to nie ma sensu sprawdzanie pozycji od 1 do i-2, ponieważ w
poprzednim obiegu zostały one już sprawdzone, nie wystąpiła na nich zamiana elementów, zatem elementy na pozycjach od 1 do
i-2 są chwilowo w dobrej kolejności względem siebie. Nie mamy tylko pewności co do pozycji i-1-szej oraz i-tej, ponieważ ostatnia
zamiana elementów umieściła na i-tej pozycji młodszy element, który być może należy wymienić z elementem na pozycji
wcześniejszej, czyli i-1. W ten sposób określimy początkową pozycję, od której rozpoczniemy sortowanie elementów w
następnym obiegu sortującym.
Ostatnia zamiana elementów wyznaczy pozycję końcową dla następnego obiegu. Wiemy, iż w każdym obiegu sortującym
najstarszy element jest zawsze umieszczany na swojej docelowej pozycji. Jeśli ostatnia zamiana elementów wystąpiła na pozycji
i-tej, to w następnym obiegu porównywanie elementów zakończymy na pozycji o 1 mniejszej - w ten sposób nie będziemy
sprawdzać już najstarszego elementu z poprzedniego obiegu.
Sortowanie prowadzimy dotąd, aż w obiegu sortującym nie wystąpi ani jedna zamiana elementów.
Teoretycznie powinno to zoptymalizować algorytm, ponieważ są sortowane tylko niezbędne fragmenty zbioru - pomijamy obszary
posortowane, które tworzą się na końcu i na początku zbioru. Oczywiście zysk nie będzie oszałamiający w przypadku zbioru
nieuporządkowanego lub posortowanego odwrotnie (może się zdarzyć, iż ewentualne korzyści czasowe będą mniejsze od czasu
wykonywania dodatkowych operacji). Jednakże dla zbiorów w dużym stopniu uporządkowanych możemy uzyskać całkiem
rozsądny algorytm sortujący prawie w czasie liniowym O(n).

Przykład:
Według opisanej powyżej metody posortujmy zbiór { 0 1 2 3 5 4 7 9 }. W zbiorze tym są tylko dwa elementy
nieuporządkowane - 5 i 4.

Obieg Zbiór Opis operacji


0 1 2 3 5 4 7 9 Pierwszy obieg, rozpoczynamy od pierwszej pozycji.
0 1 2 3 5 4 7 9
0 1 2 3 5 4 7 9 Elementy w dobrej kolejności. Zamiana miejsc nie występuje.
0 1 2 3 5 4 7 9

1 0 1 2 3 5 4 7 9 Elementy w złej kolejności. Zapamiętujemy pozycję wymiany. Jest to


jednocześnie pierwsza i ostatnia wymiana elementów w tym obiegu sortującym.
0 1 2 3 4 5 7 9
Elementy w dobrej kolejności. Zamiana miejsc nie występuje.
0 1 2 3 4 5 7 9
Koniec pierwszego obiegu. Zbiór jest już uporządkowany, ale ponieważ była
0 1 2 3 4 5 7 9 zamiana elementów, algorytm dla pewności musi wykonać jeszcze jeden obieg
sortujący.
Sortowanie rozpoczynamy od pozycji o 1 mniejszej od tej, na której wystąpiła w
0 1 2 3 4 5 7 9 poprzednim obiegu wymiana elementów. Elementy są w dobrej kolejności.
2 Dalszych sprawdzeń nie wykonujemy - kończymy na pozycji o 1 mniejszej, niż

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 46 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

2
pozycja ostatniej zamiany w poprzednim obiegu.
0 1 2 3 4 5 7 9 Koniec, zbiór jest posortowany

Chociaż podany przykład jest troszeczkę tendencyjny, to jednak pokazuje wyraźnie, iż zoptymalizowany algorytm sortowania
bąbelkowego może bardzo szybko posortować zbiory prawie uporządkowane.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - zmienna sterująca pętli, i Î N
pmin - dolna granica pozycji sortowanych elementów, pmin Î N
pmax - górna granica pozycji sortowanych elementów, pmax Î N
p - numer pozycji zamiany elementów, p Î N

Lista kroków
K01: pmin ← 1; pmax ← n - 1
K02 p ← 0
K03: Dla i = pmin, ..., pmax: wykonuj K04...K07
K04: Jeśli d[i] ≤ d[i + 1], to następny obieg pętli K03
K05: d[i] ↔ d[i + 1]
K06: Jeśli p = 0, to pmin ← i
K07: p←i
K08: Jeśli pmin > 1, to pmin ← pmin - 1
K09: pmax ← p - 1
K10: Jeśli p > 0, to idź do K02
K11: Zakończ

Schemat blokowy
Tym razem wprowadzonych zmian do algorytmu sortowania bąbelkowego jest
dużo, zatem opiszemy cały algorytm od początku.
Zmienna pmin przechowuje numer pozycji, od której rozpoczyna się sortowanie
zbioru. W pierwszym obiegu sortującym rozpoczynamy od pozycji nr 1. Zmienna
pmax przechowuje numer ostatniej pozycji do sortowania. Pierwszy obieg sortujący
kończymy na pozycji n-1, czyli na przedostatniej.
Pętla numer 1 wykonywana jest dotąd, aż w wewnętrznej pętli nr 2 nie wystąpi
żadna zamiana elementów. Zmienna p pełni w tej wersji algorytmu nieco inną rolę
niż poprzednio. Mianowicie będzie przechowywała numer pozycji, na której
algorytm ostatnio dokonał wymiany elementów. Na początku wpisujemy do p
wartość 0, która nie oznacza żadnej pozycji w zbiorze. Zatem jeśli ta wartość
zostanie zachowana, uzyskamy pewność, iż zbiór jest posortowany, ponieważ nie
dokonano wymiany elementów.
Wewnętrzną pętlę sortującą rozpoczynamy od pozycji pmin. W pętli sprawdzamy
kolejność elementu i-tego z elementem następnym. Jeśli kolejność jest zła,
wymieniamy miejscami te dwa elementy. Po wymianie sprawdzamy, czy jest to
pierwsza wymiana - zmienna p ma wtedy wartość 0. Jeśli tak, to numer pozycji, na
której dokonano wymiany umieszczamy w pmin. Numer ten zapamiętujemy
również w zmiennej p. Zwróć uwagę, iż dzięki takiemu podejściu p zawsze będzie
przechowywało numer pozycji ostatniej wymiany - jest to zasada zwana "ostatni
zwycięża".
Po sprawdzeniu elementów przechodzimy do następnej pozycji zwiększając i o 1 i
kontynuujemy pętlę, aż do przekroczenia pozycji pmax. Wtedy pętla wewnętrzna
zakończy się.
Jeśli w pętli nr 2 była dokonana zamiana elementów, to pmin zawiera numer pozycji pierwszej zamiany. Jeśli nie jest
to pierwsza pozycja w zbiorze, pmin zmniejszamy o 1, aby pętla sortująca rozpoczynała od pozycji poprzedniej w
stosunku do pozycji pierwszej zamiany elementów.
Pozycję ostatnią zawsze ustalamy o 1 mniejszą od numeru pozycji końcowej zamiany elementów.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 47 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

Na koniec sprawdzamy, czy faktycznie doszło do zamiany elementów. Jeśli tak, t o p jest większe od 0, gdyż
zawiera numer pozycji w zbiorze, na której algorytm wymienił miejscami elementy. W takim przypadku pętlę nr 1
rozpoczynamy od początku. W przeciwnym razie kończymy, zbiór jest uporządkowany.

Programy
Efekt uruchomienia programu
Sortowanie babelkowe
WERSJA NR 4
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
18 5 9 51 20 65 75 32 84 98 77 42 0 30 5 44 97 77 31 12
Po sortowaniu:
0 5 5 9 12 18 20 30 31 32 42 44 51 65 75 77 77 84 97 98

DevPascal
// Sortowanie Bąbelkowe - Wersja nr 4
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Bubble_Sort_4;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,p,pmin,pmax,x : integer;
begin
writeln(' Sortowanie babelkowe ');
writeln(' WERSJA NR 4 ');
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;
// Sortujemy
pmin := 1; pmax := N - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
if p = 0 then pmin := i;
p := i;
end;
if pmin > 1 then dec(pmin);
pmax := p - 1;
until p = 0;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Bąbelkowe - Wersja nr 4
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 48 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,p,pmin,pmax;
cout << " Sortowanie babelkowe\n"
" WERSJA NR 4\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
pmin = 0; pmax = N - 1;
do
{
p = -1;
for(i = pmin; i < pmax; i++)
if(d[i] > d[i+1])
{
swap(d[i], d[i+1]);
if(p < 0) pmin = i;
p = i;
}
if(pmin) pmin--;
pmax = p;
} while(p >= 0);
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Bąbelkowe - Wersja nr 4
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer
Dim i As Integer, p As Integer, pmin As Integer, pmax As Integer
Print " Sortowanie babelkowe "
Print " WERSJA NR 4 "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
pmin = 1: pmax = N - 1
Do
p = 0
For i = pmin To pmax
If d(i) > d(i+1) Then
Swap d(i), d(i+1)

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 49 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

If p = 0 Then pmin = i
p = i
End If
Next
If pmin > 1 Then pmin = pmin - 1
pmax = p - 1
Loop Until p = 0
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmbubblesort">
<h3 style="text-align: center">Sortowanie Bąbelkowe - wersja nr 4</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Bąbelkowe - wersja nr 4
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,p,pmin,pmax,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
pmin = 0; pmax = N - 1;
do
{
p = -1;
for(i = pmin; i < pmax; i++)
if(d[i] > d[i+1])
{
x = d[i]; d[i] = d[i+1]; d[i+1] = x;
if(p < 0) pmin = i;
p = i;
};
if(pmin) pmin--;
pmax = p;
} while(p >= 0);
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 50 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

Sortowanie Bąbelkowe - wersja nr 4


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania bąbelkowego 4 w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie bąbelkowe - Bubble Sort 4';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 6; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,p,pmin,pmax : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
pmin := 1; pmax := N - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i+1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
if p = 0 then pmin := i;
p := i;
end;
if pmin > 1 then dec(pmin);
pmax := p - 1;
until p = 0;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 51 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie bąbelkowe - Bubble Sort 4


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000007 0.028411 0.000040 0.000026 0.019901
2000 0.000013 0.120219 0.000080 0.000060 0.072574
4000 0.000025 0.476896 0.000156 0.000094 0.286498
8000 0.000051 1.906012 0.000222 0.000141 1.150969
16000 0.000114 7.639477 0.000657 0.000420 4.593252
32000 0.000280 30.786192 0.001275 0.000788 18.598717
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 52 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03
tpp
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania bąbelkowego 4
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Bąbelkowego


wersja nr 4
klasa złożoności obliczeniowej optymistyczna O(n)
klasa złożoności obliczeniowej typowa O(n2)
klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n) O(n2) O(n) O(n) O(n2)
Sortowanie bąbelkowe
wersja nr 4
tpo << tod tpp ≈ 5tpk tnp ≈ 3tod
3 5
1. Wprowadzona zmiana wpłynęła na zmianę klasy czasowej złożoności obliczeniowej przy sortowaniu zbioru
uporządkowanego z losowym elementem na końcu z O(n2) na O(n).
2. Nie zmieniła się natomiast klasa czasowej złożoności obliczeniowej przy sortowaniu zbioru uporządkowanego odwrotnie i
przy sortowaniu zbioru nieuporządkowanego. Dlatego w przypadku ogólnym klasa czasowej złożoności obliczeniowej
wynosi O(n2).
3. Z wyników testu wyciągamy wniosek, iż ta wersja algorytmu sortowania bąbelkowego jest najlepszą ze wszystkich
przedstawionych tutaj wersji. Dlatego dalsze algorytmy sortujące będziemy porównywali do wyników zoptymalizowanego
algorytmu sortowania bąbelkowego.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
Sortowanie bąbelkowe 3 ≈ 1 ≈ 1 ≈ 1 ≈ 0,08n ≈ 1
Sortowanie bąbelkowe 4 brak brak brak dobrze brak

3. Analizując wzrost prędkości algorytmu sortowania bąbelkowego w wersji 4 w stosunku do wersji 3 zauważamy, iż
wprowadzona zmiana nie zwiększyła w istotny sposób prędkości działania algorytmu w przypadku ogólnym. Zysk jest tylko
przy sortowaniu zbiorów w dużym stopniu uporządkowanych. W takich przypadkach zoptymalizowany algorytm sortowania
bąbelkowego posiada liniową czasową złożoność obliczeniową.

Zadania dla ambitnych


1. Uzasadnij powód zmiany klasy czasowej złożoności obliczeniowej z O(n2) na O(n) w tej wersji algorytmu dla przypadku sortowania
zbiorów w znacznym stopniu uporządkowanych.
2. Dlaczego w pozostałych przypadkach wzrost prędkości działania algorytmu jest niewielki?

Zobacz również na: Wersję 1 | Wersję 2 | Wersję 3 | Dwukierunkowe sortowanie bąbelkowe

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 53 / 209
Algorytmy Sortujące - Zaotymalizowane Sortowanie Bąbelkowe 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0007.php 54 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Dwukierunkowe sortowanie bąbelkowe


Bidirectional Bubble Sort
Cocktail Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja 1
Specyfikacja problemu Program w języku Pascal Podsumowanie Wersja 2
Lista kroków Program w języku C++ Zadania dla ambitnych Wersja 3
Schemat blokowy Program w języku Basic Wersja 4
Program w języku JavaScript

Algorytm
Dwukierunkowe sortowanie bąbelkowe oparte jest na
spostrzeżeniu, iż każdy obieg wewnętrznej pętli sortującej
umieszcza na właściwym miejscu element najstarszy, a
elementy młodsze przesuwa o 1 pozycję w kierunku początku
zbioru. Jeśli pętla ta zostanie wykonana w kierunku odwrotnym,
to wtedy najmłodszy element znajdzie się na swoim właściwym
miejscu, a elementy starszy przesuną się o jedną pozycję w
kierunku końca zbioru. Połączmy te dwie pętle sortując
wewnętrznie naprzemiennie w kierunku normalnym i odwrotnym,
a otrzymamy algorytm dwukierunkowego sortowania
bąbelkowego.
Wykonanie pętli sortującej w normalnym kierunku ustali
maksymalną pozycję w zbiorze, od której powinna rozpocząć sortowanie pętla odwrotna. Ta z kolei ustali minimalną pozycję w
zbiorze, od której powinna rozpocząć sortowanie pętla normalna w następnym obiegu pętli zewnętrznej. Sortowanie możemy
zakończyć, jeśli nie wystąpiła potrzeba zamiany elementów w żadnej z tych dwóch pętli.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.
Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - zmienna sterująca pętli, i Î N
pmin - dolna granica pozycji sortowanych elementów, pmin Î N
pmax - górna granica pozycji sortowanych elementów, pmax Î N
p - numer pozycji zamiany elementów, p Î N

Lista kroków
Operacja sortująca
K01: Jeśli d[i] ≤ d[i + 1], to zakończ operację sortującą
K02: d[i] ↔ d[i + 1]
K03: p←i
K04: Zakończ operację sortującą

Algorytm główny
K01: pmin ← 1; pmax ← n - 1
K02: p ← 0
K03: Dla i = pmin, pmin + 1, ..., pmax: wykonuj operację sortującą
K04: Jeśli p = 0, to zakończ

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 55 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

K05: pmax ← p - 1; p ← 0
K06: Dla i = pmax, pmax - 1, ..., pmin: wykonuj operację sortującą
K07: pmin ← p + 1
K08: Jeśli p > 0, to idź do K02
K09: Zakończ

Schemat blokowy
W algorytmie wydzieliliśmy powtarzający się fragment operacji i nazwaliśmy go
operacją sortującą. Porównuje ona dwa kolejne elementy zbioru i zamienia je
miejscami, jeśli są w złej kolejności. Po zamianie do zmiennej p trafia indeks
pierwszego z elementów pary. Podany warunek sprawdza uporządkowanie
rosnące. Jeśli chcemy posortować zbiór malejąco, relację większości należy
zastąpić relacją mniejszości.
W algorytmie występują trzy pętle. Pętla nr 1 jest pętlą warunkową i obejmuje
dwie pętle wewnętrzne nr 2 i nr 3. Pętla ta wykonywana jest dotąd, aż w
sortowanym zbiorze nie wystąpi w trakcie sortowania ani jedna zamiana miejsc
elementów.
Pętla nr 2 jest pętlą sortującą w górę. Pętla nr 3 sortuje w dół.
Na początku algorytmu ustalamy dwie granice sortowania:

- dolną w pmin
- górną w pmax.

Granice te określają indeksy elementów zbioru, które będą przeglądały pętle


sortujące nr 2 i nr 3. Początkowo granice są tak ustawione, iż obejmują cały
sortowany zbiór.
Na początku pętli nr 1 zerujemy zmienną p. Zmienna ta będzie zapamiętywać
pozycję ostatniej zamiany elementów. Jeśli po przejściu pętli sortującej nr 2 lub nr
3 zmienna p wciąż zawiera wartość 0, to nie wystąpiła żadna zamiana elementów.
Zbiór jest wtedy uporządkowany i kończymy algorytm.
Pierwszą pętlę sortującą wykonujemy kolejno dla indeksów od pmin do pmax. Po
zakończeniu pętli sprawdzamy, czy p jest równe 0. Jeśli tak, kończymy algorytm.
W przeciwnym razie p zawiera pozycję ostatniej zamiany elementów. Ponieważ pętla nr 2 ustala pozycję najstarszego elementu,
to elementy o indeksach od p do n są już właściwie uporządkowane. Dlatego dla kolejnego obiegu pętli przyjmujemy pmax o 1
mniejsze niż p.
Przed rozpoczęciem drugiej pętli zerujemy p. Jest to dosyć ważne. Załóżmy, iż zbiór został już uporządkowany w poprzedniej pętli
nr 2, lecz wystąpiła tam zamiana elementów. Jeśli nie wyzerujemy p, to następna pętla sortująca nie zmieni zawartości tej
zmiennej i p zachowa wartość większą od 0. Zatem pętla główna nr 1 nie zakończy się i algorytm wykona niepotrzebnie jeszcze
jeden pusty obieg. Niby nic, a jednak...
Pętla nr 3 sortuje w kierunku odwrotnym od pmax do pmin. Po jej zakończeniu p zawiera indeks ostatniej zamiany elementów.
Podobnie jak poprzednio zbiór jest uporządkowany od elementu nr 1 do p. Zatem dla kolejnych obiegów przyjmujemy pmin o 1
większe od p. Jeśli p jest równe 0, kończymy algorytm. W przeciwnym razie kontynuujemy pętlę nr 1.

Programy
Efekt uruchomienia programu
Dwukierunkowe Sortowanie babelkowe
----------------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
22 67 9 15 4 3 21 40 66 83 89 38 31 42 92 55 3 87 48 50
Po sortowaniu:
3 3 4 9 15 21 22 31 38 40 42 48 50 55 66 67 83 87 89 92

DevPascal
// Dwukierunkowe Sortowanie Bąbelkowe
//-----------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Bidirectional_Bubble_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 56 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

// Program główny
//---------------
var
i,p,pmin,pmax,x: integer;
begin
writeln('Dwukierunkowe sortowanie babelkowe');
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;
// Sortujemy
pmin := 1; pmax := N - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := i;
end;
if p = 0 then break;
pmax := p - 1;
p := 0;
for i := pmax downto pmin do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := i;
end;
pmin := p + 1;
until p = 0;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Dwukierunkowe Sortowanie Bąbelkowe
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,pmin,pmax,p;
cout << "Dwukierunkowe Sortowanie babelkowe\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
pmin = 0; pmax = N - 2;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 57 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

do
{
p = -1;
for(i = pmin; i <= pmax; i++)
if(d[i] > d[i + 1])
{
swap(d[i], d[i + 1]);
p = i;
}
if(p < 0) break;
pmax = p - 1;
p = -1;
for(i = pmax; i >= pmin; i--)
if(d[i] > d[i + 1])
{
swap(d[i], d[i + 1]);
p = i;
}
pmin = p + 1;
} while(p >= 0);
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Dwukierunkowe Sortowanie Bąbelkowe
'-----------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer
Dim i As Integer, p As Integer, pmin As Integer, pmax As Integer
Print "Dwukierunkowe sortowanie babelkowe"
Print "----------------------------------"
Print " (C)2005 Jerzy Walaszek"
Print
' Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
pmin = 1: pmax = N - 1
Do
p = 0
For i = pmin To pmax
If d(i) > d(i + 1) Then
Swap d(i), d(i + 1)
p = i
End If
Next
If p = 0 Then Exit Do
pmax = p - 1
p = 0
For i = pmax To pmin Step -1
If d(i) > d(i + 1) Then
Swap d(i), d(i + 1)
p = i
End If
Next
pmin = p + 1
Loop Until p = 0
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter...";
Sleep
End

JavaScript
<html>
<head>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 58 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

</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="frmbubblesort">
<h3 style="text-align: center">Sortowanie Bąbelkowe - wersja nr 3</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Bąbelkowe - wersja nr 3
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,pmin,pmax,p,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
pmin = 0; pmax = N - 2;
do
{
p = -1;
for(i = pmin; i <= pmax; i++)
if(d[i] > d[i + 1])
{
x = d[i]; d[i] = d[i+1]; d[i+1] = x;
p = i;
}
if(p < 0) break;
pmax = p - 1;
p = -1;
for(i = pmax; i >= pmin; i--)
if(d[i] > d[i + 1])
{
x = d[i]; d[i] = d[i+1]; d[i+1] = x;
p = i;
}
pmin = p + 1;
} while(p >= 0);
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Dwukierunkowe Sortowanie Bąbelkowe


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badanie algorytmów sortowania

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 59 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

Badanie algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu dwukierunkowego sortowania bąbelkowego w środowisku opisanym
we wstępie. Program testujący jest następujący:
DLA
DevPascal GENIUSZA
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Dwukierunkowe sortowanie bąbelkowe';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 6; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,p,pmin,pmax : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
pmin := 1; pmax := n - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := i;
end;
if p = 0 then break;
pmax := p - 1;
p := 0;
for i := pmax downto pmin do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i+1]; d[i+1] := x;
p := i;
end;
pmin := p + 1;
until p = 0;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 60 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości
czasów wykonania, dlatego w celach porównawczych proponuję uruchomić podany program na komputerze
czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Dwukierunkowe sortowanie bąbelkowe


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000008 0.025453 0.000042 0.000035 0.016423
2000 0.000015 0.101098 0.000085 0.000076 0.062626
4000 0.000027 0.400720 0.000157 0.000141 0.241540
8000 0.000051 1.608819 0.000226 0.000232 0.968169
16000 0.000114 6.432362 0.000663 0.000573 3.876952
32000 0.000282 25.828298 0.001269 0.001122 15.551078
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 61 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu dwukierunkowego sortowania
bąbelkowego wyciągamy następujące wnioski:
Cechy Algorytmu Dwukierunkowego
Sortowania Bąbelkowego
klasa złożoności obliczeniowej optymistyczna O(n)
klasa złożoności obliczeniowej typowa O(n2)
klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n) O(n2) O(n) O(n) O(n2)
Dwukierunkowe
sortowanie bąbelkowe
tpo << tod tpp ≈ 9tpk tnp ≈ 3tod
8 5
1. W przypadku zbioru posortowanego odwrotnie oraz zbioru nieuporządkowanego algorytm wykonuje się w czasie
proporcjonalnym do kwadratu liczby elementów, zatem jego typowa czasowa złożoność obliczeniowa jest klasy O(n2).
2. Zbiór nieuporządkowany sortowany jest szybciej od zbioru uporządkowanego odwrotnie. Wnioskujemy zatem, iż zbiór
uporządkowany odwrotnie jest najtrudniejszym zadaniem dla tego algorytmu.
3. Przy sortowaniu zbiorów w znacznym stopniu posortowanych klasa czasowej złożoności obliczeniowej redukuje się do
O(n), jest zatem bardzo korzystna.
4. W porównaniu do zoptymalizowanego algorytmu bąbelkowego w wersji 4 algorytm dwukierunkowego sortowania
bąbelkowego nie wykazuje specjalnie nowych własności. Obserwujemy jedynie wyrównanie czasów sortowania zbioru
uporządkowanego z jednym elementem losowym na początku i na końcu.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

Sortowanie bąbelkowe 4 7 7 6
≈1 ≈ ≈1 ≈ ≈
Dwukierunkowe sortowanie bąbelkowe
6 10 5
brak lepiej brak gorzej lepiej

5. Jeśli porównamy prędkości obu algorytmów, to obecna wersja radzi sobie nieco lepiej w przypadku zbiorów
uporządkowanych odwrotnie oraz zbiorów nieuporządkowanych. W pozostałych sytuacjach jest bez zmian, lub nawet
gorzej.

Zadania dla ambitnych


1. Uzasadnij wyrównanie czasów tpp i tpk w algorytmie dwukierunkowego sortowania bąbelkowego.

Zobacz również na: Wersję 1 | Wersję 2 | Wersję 3 | Wersję 4

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 62 / 209
Algorytmy Sortujące - Sortowanie Bąbelkowe Dwukierunkowe 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0008.php 63 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie przez wybór


Selection Sort
Podrozdziały
Algorytm Programy Badanie algorytmów sortujących
Specyfikacja problemu Program w języku Pascal Podsumowanie
Lista kroków Program w języku C++ Zadania dla ambitnych
Schemat blokowy Program w języku Basic
Program w języku JavaScript

Algorytm
Idea algorytmu sortowania przez wybór jest bardzo prosta.
Załóżmy, iż chcemy posortować zbiór liczbowy rosnąco. Zatem
element najmniejszy powinien znaleźć się na pierwszej pozycji.
Szukamy w zbiorze elementu najmniejszego i wymieniamy go
z elementem na pierwszej pozycji. W ten sposób element
najmniejszy znajdzie się na swojej docelowej pozycji.
W identyczny sposób postępujemy z resztą elementów
należących do zbioru. Znów wyszukujemy element najmniejszy i
zamieniamy go z elementem na drugiej pozycji. Otrzymamy dwa
posortowane elementy. Procedurę kontynuujemy dla pozostałych
elementów dotąd, aż wszystkie będą posortowane.
Algorytm sortowania przez wybór posiada klasę czasowej złożoności obliczeniowej równą O(n2). Sortowanie odbywa się w
miejscu.

Przykład:
Dla przykładu posortujmy tą metodą zbiór {4 7 2 9 3}. Kolorem zielonym oznaczyliśmy elementy zbioru, które są już
posortowane.

Zbiór Opis operacji


4 7 2 9 3 Wyszukujemy najmniejszy element w zbiorze. Jest nim liczba 2.
2 7 4 9 3 Znaleziony element minimalny wymieniamy z pierwszym elementem zbioru - liczbą 4
2 7 4 9 3 Wśród pozostałych elementów wyszukujemy element najmniejszy. Jest nim liczba 3.
2 3 4 9 7 Znaleziony element minimalny wymieniamy z drugim elementem zbioru - liczbą 7.
2 3 4 9 7 Znajdujemy kolejny element minimalny - liczbę 4.
2 3 4 9 7 Wymieniamy go z samym sobą - element ten nie zmienia zatem swojej pozycji w zbiorze.
2 3 4 9 7 Znajdujemy kolejny element minimalny
2 3 4 7 9 Wymieniamy go z liczbą 9

2 3 4 7 9 Ostatni element jest zawsze na właściwej pozycji. Sortowanie zakończone

Podana metoda sortuje zbiór rosnąco. Jeśli chcemy posortować zbiór malejąco, to zamiast elementu minimalnego poszukujemy
elementu maksymalnego. Pozostała część procedury sortującej nie ulega zmianie.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i, j - zmienne sterujące pętli, i, j Î N

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 64 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

pmin - pozycja elementu minimalnego w zbiorze d[ ], pmin Î N

Lista kroków
K01: Dla j = 1, 2, ..., n - 1: wykonuj K02...K04
K02: pmin ← j
K03: Dla i = j + 1, j + 2, ..., n: jeśli d[i] < d[pmin], to pmin ← i
K04: d[j] ↔ d[pmin]
K05: Zakończ

Schemat blokowy
Pętla zewnętrzna sterowana zmienną j wyznacza kolejne elementy zbioru o indeksach od 1
do n - 1, w których zostaną umieszczone elementy minimalne. Na początku tej pętli
zakładamy, iż elementem minimalnym jest element d[j] i zapamiętujemy jego indeks w
zmiennej pmin.
W pętli numer 2 sterowanej zmienną i porównujemy pozostałe elementy zbioru z elementem
d[pmin]. Jeśli element zbioru d[i] jest mniejszy od elementu d[pmin], to znaleźliśmy nowy
element minimalny. W takim przypadku zapamiętujemy jego pozycję w pmin i kontynuujemy
pętlę wewnętrzną.
Po zakończeniu pętli wewnętrznej pmin zawiera indeks elementu minimalnego. Zamieniamy
miejscami element d[j] z elementem d[pmin]. Dzięki tej operacji element minimalny znajduje
się na swojej docelowej pozycji. Zwiększamy j przechodząc do kolejnego elementu zbioru i
kontynuujemy pętlę zewnętrzną.

Programy
Efekt uruchomienia programu
Sortowanie przez wybor
------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
98 49 73 16 64 25 5 83 54 51 80 3 98 26 86 87 80 68 5 11
Po sortowaniu:
3 5 5 11 16 25 26 49 51 54 64 68 73 80 80 83 86 87 98 98

DevPascal
// Sortowanie Przez Wybór
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Selection_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,j,x,pmin : integer;
begin
writeln(' Sortowanie przez wybor ');
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);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 65 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

writeln('Przed sortowaniem:'); writeln;


for i := 1 to N do write(d[i] : 4);
writeln;
// Sortujemy
for j := 1 to N - 1 do
begin
pmin := j;
for i := j + 1 to N do
if d[i] < d[pmin] then pmin := i;
x := d[pmin]; d[pmin] := d[j]; d[j] := x;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Przez Wybór
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j,pmin;
cout << " Sortowanie przez wybor\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
for(j = 0; j < N - 1; j++)
{
pmin = j;
for(i = j + 1; i < N; i++)
if(d[i] < d[pmin]) pmin = i;
swap(d[pmin], d[j]);
}
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Przez Wybór
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 66 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

Dim i As Integer, j As Integer, pmin As Integer


Print " Sortowanie przez wybor "
Print "------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Najpierw wypełniamy tablicę d() liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = 1 To N - 1
pmin = j
For i = j + 1 To N
If d(i) < d(pmin) Then pmin = i
Next
Swap d(pmin),d(j)
Next
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmselectionsort">
<h3 style="text-align: center">Sortowanie Przez Wybór</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Przez Wybór
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,pmin,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = 0; j < N - 1; j++)
{
pmin = j;
for(i = j + 1; i < N; i++)
if(d[i] < d[pmin]) pmin = i;
x = d[pmin]; d[pmin] = d[j]; d[j] = x;
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 67 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

for(i = 0; i < N; i++) t += d[i] + " ";


document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Przez Wybór


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania przez wybór w środowisku opisanym we wstępie. Program
testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie przez wybór';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 6; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j,pmin : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
for j := 1 to n - 1 do
begin
pmin := j;
for i := j + 1 to n do
if d[i] < d[pmin] then pmin := i;
x := d[pmin]; d[pmin] := d[j]; d[j] := x;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 68 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie przez wybór


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.002724 0.002909 0.002791 0.002780 0.003110
2000 0.011507 0.012866 0.011278 0.011224 0.011862
4000 0.045771 0.049455 0.045857 0.045861 0.047035
8000 0.183433 0.198379 0.187596 0.187755 0.186893
16000 0.737399 0.797531 0.743703 0.741200 0.748871
32000 3.236753 3.429465 3.221679 3.219949 3.234469
-------------------------------------------------------------------
Koniec

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 69 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):


n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania przez wybór
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Przez Wybór


klasa złożoności obliczeniowej optymistyczna O(n2)

klasa złożoności obliczeniowej typowa O(n2)


klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność NIE

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp

O(n2) O(n2) O(n2) O(n2) O(n2)


Sortowanie przez wybór
tpo ≈ tod ≈ tpp ≈ tpk ≈ tnp

1. Wszystkie badane przez nas czasy sortowania są proporcjonalne do kwadratu liczby elementów porządkowanego zbioru.
Klasa czasowej złożoności obliczeniowej algorytmu sortowania przez wybór wynosi O(n2).
2. Wszystkie badane czasy sortowania są praktycznie takie same.
3. Algorytm nie uwzględnia faktu posortowania zbioru. Jednakże również nie wyróżnia on przypadku posortowania zbioru w
kierunku odwrotnym. Zatem można wysunąć wniosek, iż dla tego algorytmu złożoność czasowa nie zależy od rozkładu
elementów w sortowanym zbiorze.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
3 14 8
Sortowanie bąbelkowe 4 ≈ ≈9 ≈ ≈ ≈6
n n n
Sortowanie przez wybór
źle dobrze źle źle dobrze

4. Porównując prędkości algorytmów zoptymalizowanego sortowania bąbelkowego i sortowania przez wybór dochodzimy do
wniosku, iż ten drugi w przypadku zbiorów posortowanych odwrotnie oraz nieposortowanych jest kilkakrotnie szybszy.
Jednakże dla zbiorów w znacznym stopniu uporządkowanych algorytm sortowania bąbelkowego nie daje mu żadnych szans
- nic w tym dziwnego, ponieważ zgodnie z naszymi badaniami, algorytm sortowania bąbelkowego posiada w tych
przypadkach liniową klasę czasowej złożoności obliczeniowej, natomiast algorytm sortowania przez wybór ma dla każdego
zestawu danych czasową złożoność obliczeniową proporcjonalną do kwadratu liczby sortowanych elementów.

Zadania dla ambitnych


1. Na podstawie algorytmu sortowania przez wybór uzasadnij, iż czas sortowania nie jest zależny od rozkładu elementów w porządkowanym
zbiorze.
2. Uzasadnij, że algorytm sortowania przez wybór nie jest stabilny.

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 70 / 209
Algorytmy Sortujące - Sortowanie Przez Wybór 2014-10-03

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0009.php 71 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie przez wstawianie


Insertion Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów Wersja z wyszukiwaniem
Wstawianie elementu na listę Program w języku Pascal sortujących binarnym
uporządkowaną Program w języku C++ Podsumowanie
Specyfikacja problemu Program w języku Basic Zadania dla ambitnych
Lista kroków Program w języku
Schemat blokowy JavaScript

Algorytm
Algorytm sortowania przez wstawianie można porównać do
sposobu układania kart pobieranych z talii. Najpierw bierzemy
pierwszą kartę. Następnie pobieramy kolejne, aż do wyczerpania
talii. Każdą pobraną kartę porównujemy z kartami, które już
trzymamy w ręce i szukamy dla niej miejsca przed pierwszą
kartą starszą (młodszą w przypadku porządku malejącego). Gdy
znajdziemy takie miejsce, rozsuwamy karty i nową wstawiamy
na przygotowane w ten sposób miejsce (stąd pochodzi nazwa
algorytmu - sortowanie przez wstawianie, ang. Insertion Sort).
Jeśli nasza karta jest najstarsza (najmłodsza), to umieszczamy
ją na samym końcu. Tak porządkujemy karty. A jak przenieść tę
ideę do świata komputerów i zbiorów liczbowych?
Algorytm sortowania przez wstawianie będzie składał się z dwóch pętli. Pętla główna (zewnętrzna) symuluje pobieranie kart, czyli
w tym wypadku elementów zbioru. Odpowiednikiem kart na ręce jest tzw. lista uporządkowana (ang. sorted list), którą
sukcesywnie będziemy tworzyli na końcu zbioru (istnieje też odmiana algorytmu umieszczająca listę uporządkowaną na początku
zbioru). Pętla sortująca (wewnętrzna) szuka dla pobranego elementu miejsca na liście uporządkowanej. Jeśli takie miejsce
zostanie znalezione, to elementy listy są odpowiednio rozsuwane, aby tworzyć miejsce na nowy element i element wybrany przez
pętlę główną trafia tam. W ten sposób lista uporządkowana rozrasta się. Jeśli na liście uporządkowanej nie ma elementu
większego od wybranego, to element ten trafia na koniec listy. Sortowanie zakończymy, gdy pętla główna wybierze wszystkie
elementy zbioru.
Algorytm sortowania przez wstawianie posiada klasę czasowej złożoności obliczeniowej równą O(n2). Sortowanie odbywa się w
miejscu.

Wstawianie elementu na listę uporządkowaną


Najważniejszą operacją w opisywanym algorytmie sortowania jest wstawianie wybranego elementu na listę uporządkowaną.
Zasady są następujące:

1. Na początku sortowania lista uporządkowana zawiera tylko jeden, ostatni element zbioru. Jednoelementowa lista jest
zawsze uporządkowana.
2. Ze zbioru zawsze wybieramy element leżący tuż przed listą uporządkowaną. Element ten zapamiętujemy w zewnętrznej
zmiennej. Miejsce, które zajmował, możemy potraktować jak puste.
3. Wybrany element porównujemy z kolejnymi elementami listy uporządkowanej.
4. Jeśli natrafimy na koniec listy, element wybrany wstawiamy na puste miejsce - lista rozrasta się o nowy element.
5. Jeśli element listy jest większy od wybranego, to element wybrany wstawiamy na puste miejsce - lista rozrasta się o nowy
element.
6. Jeśli element listy nie jest większy od wybranego, to element listy przesuwamy na puste miejsce. Dzięki tej operacji puste
miejsce wędruje na liście przed kolejny element. Kontynuujemy porównywanie, aż wystąpi sytuacja z punktu 4 lub 5.

Przykład:
Dla przykładu wstawmy wg opisanej metody pierwszy element zbioru listę uporządkowaną utworzoną z pozostałych
elementów {8 4 5 6 9}. Elementy listy uporządkowanej zaznaczyliśmy kolorem zielonym. Puste miejsce
zaznaczyliśmy kolorem białym:

Zbiór Opis operacji


8 4 5 6 9 Element 8 znajduje się tuż przed listą uporządkowaną.
8 Wybieramy ze zbioru element 8. Zajmowane przez niego miejsce staje się puste.
4 5 6 9

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 72 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

8 Porównujemy 8 z pierwszym elementem listy uporządkowanej, z liczbą 4.


4 5 6 9
8 Ponieważ element 4 jest mniejszy od elementu wybranego 8, przesuwamy go na puste
4 <<< 5 6 9 miejsce. Zwróć uwagę, iż puste miejsce wędruje w kierunku końca listy uporządkowanej.
8
4 5 6 9 Porównujemy 8 z kolejnym elementem listy uporządkowanej, z liczbą 5.

8 5 jest5 mniejsze od 8, zatem wędruje na puste miejsce, które przesuwa się przed kolejny
4 5 <<< 6 9 element listy uporządkowanej, liczbę 6.
8 Porównujemy 8 z 6.
4 5 6 9
8 6 jest mniejsze od 8, wędruje na puste miejsce.
4 5 6 <<< 9
8 Porównujemy 8 z 9.
4 5 6 9
Tym razem element wybrany wędruje na puste miejsce, ponieważ jest mniejszy od
4 5 6 8 9 elementu 9 listy uporządkowanej. Operacja wstawiania jest zakończona. Lista rozrasta
się o jeden element.

Przykład:
Wykorzystajmy podane informacje do posortowania opisywaną metodą zbioru { 7 3 8 5 2 }.

Zbiór Opis operacji


7 3 8 5 2 Ostatni element jest zalążkiem listy uporządkowanej.
5
7 3 8 2 Ze zbioru wybieramy element leżący tuż przed listą uporządkowaną.

5
7 3 8 2 Wybrany element porównujemy z elementem listy.

5 Ponieważ element listy jest mniejszy od elementu wybranego, to przesuwamy go na


7 3 8 2 <<< puste miejsce.

7 3 8 2 5 Na liście nie ma już więcej elementów do porównania, więc element wybrany wstawiamy
na puste miejsce. Lista uporządkowana zawiera już dwa elementy.
8 Ze zbioru wybieramy 8
7 3 2 5
8 8 porównujemy z 2
7 3 2 5
8
7 3 2 <<< 5 2 jest mniejsze, zatem przesuwamy je na puste miejsce.

8
7 3 2 5 8 porównujemy z 5

8
7 3 2 5 <<< 5 jest mniejsze, przesuwamy je na puste miejsce

7 3 2 5 8 Lista nie zawiera więcej elementów, zatem 8 wstawiamy na puste miejsce. Na liście
uporządkowanej mamy już trzy elementy.
3
7 2 5 8 Ze zbioru wybieramy 3

3 3 porównujemy z 2
7 2 5 8
3 2 jest mniejsze, wędruje zatem na puste miejsce
7 2 <<< 5 8
3 3 porównujemy z 5.
7 2 5 8

7 2 3 5 8 Tym razem mniejszy jest element wybrany. Znaleźliśmy jego miejsce na liście, więc
wstawiamy go na puste miejsce. Lista zawiera już 4 elementy.
7
2 3 5 8 Ze zbioru wybieramy ostatni element - liczbę 7.

7
2 3 5 8 7 porównujemy z 2

7
2 <<< 3 5 8 2 jest mniejsze, przesuwamy je na puste miejsce

7
2 3 5 8 7 porównujemy z 3

7
2 3 <<< 5 8 3 jest mniejsze, przesuwamy je na puste miejsce

7
2 3 5 8 7 porównujemy z 5

7
2 3 5 <<< 8 5 jest mniejsze, przesuwamy je na puste miejsce

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 73 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

7
2 3 5 8 7 porównujemy z 8

2 3 5 7 8 Element wybrany jest mniejszy, wstawiamy go na puste miejsce. Lista uporządkowana


objęła już cały zbiór. Sortowanie jest zakończone.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.
Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i, j - zmienne sterujące pętli, i, j Î N
x - zawiera wybrany ze zbioru element.

Lista kroków
K01: Dla j = n - 1, n - 2, ..., 1: wykonuj K02...K04
K02: x ← d[j]; i ← j + 1
K03: Dopóki ( i ≤ n ) ( x > d[i] ): wykonuj d[i - 1] ← d[i]; i ← i + 1
K04: d[i - 1] ← x
K05: Zakończ

Schemat blokowy
Pętlę główną rozpoczynamy od przedostatniej pozycji w zbiorze. Element na ostatniej
pozycji jest zalążkiem listy uporządkowanej. Dlatego licznik pętli nr 1 przyjmuje wartość
początkową j = n - 1.
Ze zbioru wybieramy element d[j] i umieszczamy go w zmiennej pomocniczej x. Miejsce
zajmowane przez ten element staje się puste.

Uwaga techniczna
W rzeczywistości na pozycji j pozostaje dalej ten sam element. Jednakże
zapamiętaliśmy jego wartość, zatem pozycja ta może być zapisana inną informacją -
elementu nie utracimy, ponieważ przechowuje go zmienna x. Dlatego pozycję tę możemy
potraktować jako pustą, tzn. z nieistotną zawartością.

Pętlę wewnętrzną rozpoczynamy od pozycji następnej w stosunku do j. Pozycja ta zawiera


pierwszy element listy uporządkowanej, która tworzona jest na końcu sortowanego zbioru.
Pętlę wewnętrzną przerywamy w dwóch przypadkach - gdy licznik pętli wyjdzie poza indeks
ostatniego elementu w zbiorze lub gdy element wybrany, przechowywany w zmiennej
pomocniczej x, jest mniejszy lub równy bieżąco testowanemu elementowi listy
uporządkowanej (dla sortowania malejącego należy zastosować w tym miejscu relację
większy lub równy). W obu przypadkach na puste miejsce ma trafić zawartość zmiennej x i pętla zewnętrzna jest kontynuowana.
Zauważ, iż pozycja tego miejsca w zbiorze jest równa i - 1.
Jeśli żaden z warunków przerwania pętli wewnętrznej nr 2 nie wystąpi, to przesuwamy bieżący element listy na puste miejsce i
kontynuujemy pętlę wewnętrzną.
Podsumowując: pętla zewnętrzna wybiera ze zbioru kolejne elementy o indeksach od n - 1 do 1, pętla wewnętrzna szuka dla
wybranych elementów miejsca wstawienia na liście uporządkowanej, po znalezieniu którego pętla zewnętrzna wstawia wybrany
element na listę. Gdy pętla zewnętrzna przebiegnie wszystkie elementy o indeksach od n - 1 do 1, zbiór będzie posortowany.
Algorytm posiada klasę czasowej złożoności obliczeniowej równą O(n2). Sortowanie odbywa się w miejscu.

Programy
Efekt uruchomienia programu
Sortowanie przez wstawianie
-----------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
56 5 18 74 83 24 13 4 50 74 63 83 65 65 63 40 81 69 60 84
Po sortowaniu:
4 5 13 18 24 40 50 56 60 63 63 65 65 69 74 74 81 83 83 84

DevPascal

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 74 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

// Sortowanie Przez Wstawianie


//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Insertion_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,j,x : integer;
begin
writeln(' Sortowanie przez wstawianie ');
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;
// Sortujemy
for j := N - 1 downto 1 do
begin
x := d[j];
i := j + 1;
while (i <= N) and (x > d[i]) do
begin
d[i - 1] := d[i];
inc(i);
end;
d[i - 1] := x;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Przez Wstawianie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j,x;
cout << " Sortowanie przez wstawianie\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 75 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

for(i = 0; i < N; i++) cout << setw(4) << d[i];


cout << endl;
// Sortujemy
for(j = N - 2; j >= 0; j--)
{
x = d[j];
i = j + 1;
while((i < N) && (x > d[i]))
{
d[i - 1] = d[i];
i++;
}
d[i - 1] = x;
}
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Przez Wstawianie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer
Dim i As Integer, j As Integer, x As Integer
Print " Sortowanie przez wstawianie "
Print "-----------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Najpierw wypełniamy tablicę d() liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = N - 1 To 1 Step -1
x = d(j)
i = j + 1
While (i <= N) And (x > d(i))
d(i - 1) = d(i)
i = i + 1
Wend
d(i - 1) = x
Next
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frminsertionsort">
<h3 style="text-align: center">Sortowanie Przez Wstawianie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Sortuj" name="B1">

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 76 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

</p>
<p id="t_out" style="TEXT-ALIGN: center">...</p>
</form>
<script language=javascript>
// Sortowanie Przez Wstawianie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = N - 2; j >= 0; j--)
{
x = d[j];
i = j + 1;
while((i < N) && (x > d[i]))
{
d[i - 1] = d[i];
i++;
}
d[i - 1] = x;
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Przez Wstawianie


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania przez wstawianie w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie przez wstawianie';
K1 = '--------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 77 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

MAX_LN = 6; // określa ostatnie LN


LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
for j := n - 1 downto 1 do
begin
x := d[j];
i := j + 1;
while (i <= n) and (x > d[i]) do
begin
d[i - 1] := d[i];
inc(i);
end;
d[i - 1] := x;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 78 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie przez wstawianie


--------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000040 0.005941 0.000060 0.000074 0.002360
2000 0.000080 0.017525 0.000088 0.000113 0.009178
4000 0.000159 0.069866 0.000175 0.000218 0.035947
8000 0.000318 0.290939 0.000387 0.000382 0.141822
16000 0.000671 1.129738 0.000790 0.000842 0.572611
32000 0.001324 5.284645 0.001525 0.001644 2.443392
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania przez wstawianie
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Przez Wstawianie


klasa złożoności obliczeniowej optymistyczna O(n)
klasa złożoności obliczeniowej typowa O(n2)
klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 79 / 209
Algorytmy Sortujące - Sortowanie Przez Wstawianie 2014-10-03

O(n) O(n2) O(n) O(n) O(n2)


Sortowanie przez wstawianie
tpo << tod tpp ≈ tpk tnp ≈ 1tod
2
1. Algorytm wykorzystuje fakt posortowania zbioru. Dla zbiorów w znacznym stopniu uporządkowanych klasa czasowej
złożoności obliczeniowej algorytmu jest prawie liniowa. Czas sortowania takich zbiorów jest bardzo krótki.
2. Najbardziej niekorzystnym przypadkiem jest sortowanie zbioru posortowanego odwrotnie - czas sortowania jest najdłuższy.
Czas sortowania zbioru o losowym rozkładzie elementów jest o połowę krótszy.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

Sortowanie przez wybór 3 2 2 3 4


≈ n ≈ ≈ n ≈ n ≈
Sortowanie przez wstawianie 40 3 30 50 3
dobrze źle dobrze dobrze dobrze

3. Analiza wzrostu prędkości algorytmu sortowania przez wstawianie w stosunku do algorytmu sortowania przez wybór
pokazuje, iż obecny algorytm jest dużo lepszy w przypadku zbiorów w znacznym stopniu uporządkowanych. Również
zbiory o losowym rozkładzie elementów będą posortowane szybciej. Jedynie w przypadku pesymistycznym, gdy zbiór jest
posortowany odwrotnie, algorytm jest wolniejszy od algorytmu sortowania przez wybór. Te cechy czynią algorytm
sortowania przez wstawianie zalecanym, prostym algorytmem sortującym klasy O(n2).

Zadania dla ambitnych


1. Porównaj wzrost prędkości algorytmu sortowania przez wstawianie z algorytmem sortowania bąbelkowego w wersji nr 4. Wyciągnij
odpowiednie wnioski.
2. Udowodnij, iż algorytm ma liniową klasę czasowej złożoności obliczeniowej przy sortowaniu zbiorów uporządkowanych z jednym
elementem nie na swoim miejscu.
3. Wyznacz liczbę porównań przy sortowaniu n-elementowego (n > 1) zbioru uporządkowanego z wyjątkiem ostatniego elementu, który jest
mniejszy od wszystkich pozostałych elementów zbioru.
4. Wyznacz liczbę przesunięć elementów listy uporządkowanej przy sortowaniu n-elementowego (n > 1) zbioru posortowanego odwrotnie.

Zobacz również na: wersję z wyszukiwaniem binarnym

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0010.php 80 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Binarne sortowanie przez wstawianie


Binary Insertion Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Wersja podstawowa
Specyfikacja problemu Program w języku Pascal Podsumowanie
Lista kroków Program w języku C++ Zadania dla ambitnych
Schemat blokowy Program w języku Basic
Program w języku JavaScript

Algorytm
Al gory t m sortowania przez wstawianie wykorzystuje
poszukiwanie liniowe w celu znalezienia miejsca wstawiania
wybranego elementu na liście uporządkowanej. Są trzy
możliwości:
1. Element wybrany jest mniejszy lub równy pierwszemu
elementowi listy uporządkowanej (w porz ądk u malejącym
element ten jest większy lub równy). W takim przypadku
wykonane zostanie tylko jedno porównanie i element wybrany
wróci z powrotem na swoje poprzednie miejsce.
2. Element wybrany jest większy od ostatniego elementu listy
uporządkowanej (w porządku malejącym element wybrany jest
mniejszy od ostatniego elementu listy uporządkowanej). Jeśli element wybrany znajduje się na j-tej pozycji, to algorytm musi
wykonać (n - j) porównań elementy wybranego z kolejnymi elementami listy oraz tyle samo przesunięć elementów listy na puste
miejsce.
3. W pozostałych przypadkach element wybrany trafia do wnętrza listy uporządkowanej. Statystycznie będzie to jej środek, zatem
średnio algorytm wykona 0,5 • (n - j) porównań i przesunięć elementów.
Ponieważ lista jest uporządkowana, możemy do jej przeszukania wykorzystać algorytm wyszukiwania binarnego, który ma
klasę czasowej złożoności obliczeniowej równą O(log n), jest zatem niesamowicie szybki. Zasada przeszukiwania binarnego jest
bardzo prosta. Wyznaczamy element środkowy listy. Sprawdzamy, czy wstawiany element jest mniejszy lub równy (przy
sortowaniu malejącym większy lub równy) od elementu środkowego listy. Jeśli tak, to za nowy przedział przyjmujemy pierwszą
część listy, w przeciwnym razie drugą. Operację tę powtarzamy dotąd, aż przedział poszukiwań skurczy się do 1 elementu (nie
można wtedy wyznaczać połówek). Pozycja tego elementu wyznaczy nam miejsce wstawienia. Musimy tylko przesunąć o jedną
pozycję wstecz wszystkie elementy od pozycji (j + 1) do znalezionego miejsca na liście, a następnie wstawić na zwolnione
miejsce element wybrany.
Brzmi super - zmniejszymy liczbę porównań. Czy jest to jednak opłacalne, zobaczymy później, po analizie czasów wykonania
algorytmu.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.

Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - indeks środkowego elementu listy uporządkowanej, i Î N
j - licznik obiegów pętli zewnętrznej, indeks wybranego elementu, j Î N
ip, ik - początkowa i końcowa pozycja indeksów w partycji listy uporządkowanej, ip, ik Î N
x - zawiera wybrany ze zbioru element

Lista kroków
K01: Dla j = n - 1, n - 2,...,1: wykonuj K02...K07
K02: x ← d[j]; ip ← j; ik ← n + 1
K03: Dopóki ik - ip > 1: wykonuj K04...K05

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 81 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

K04: i ← (ip + ik) div 2


K05: Jeśli x ≤ d[i], to ik ← i
inaczej ip ← i
K06: Dla i = j, j + 1, ..., ip - 1: wykonuj d[i] ← d[i + 1]
K07: d[ip] ← x
K08: Zakończ

Schemat blokowy
Algorytm zoptymalizowanego sortowania przez wstawianie zbudowany jest z trzech pętli:
- pętla zewnętrzna nr 1 wybiera ze zbioru element leżący przed listą uporządkowaną.
- pętla wewnętrzna nr 2 poszukuje miejsca wstawienia wybranego elementu na liście
uporządkowanej wykorzystując algorytm wyszukiwania binarnego.
- pętla wewnętrzna nr 3 przesuwa elementy listy, aby zrobić miejsce dla elementu
wybranego.
Na początku algorytmu inicjujemy licznik j pętli zewnętrznej nr 1. Będzie ona przebiegała
przez kolejne indeksy elementów sortowanego zbioru od n - 1 do 1. Na początku tej pętli
umieszczamy w zmiennej pomocniczej x element wybrany. Element ten znajduje się tuż
przed listą uporządkowaną, która tworzona jest na końcu zbioru. Dalej ustawiamy dwa
graniczne indeksy ip i ik , które definiują pozycję elementów na liście uporządkowanej.
Zwróć uwagę, iż faktycznie indeks ip wskazuje pozycję przed listą, a ik wskazuje
pozycję za listą. Jest to potrzebne po to, aby pętla warunkowa nr 2 wykonała się
przynajmniej jeden raz.
Rozpoczyna się pętla warunkowa nr 2. Jest to typowa pętla while, w której warunek
kontynuacji sprawdzamy na początku. Pętla kontynuuje się dopóki partycja listy
uporządkowanej zdefiniowana indeksami ip i ik zawiera więcej niż 1 element, gdyż tylko
wtedy można dokonać podziału na dwie mniejsze partycje. Gdy pętla ta się zakończy,
zmienna ip zawiera indeks pozycji wstawiania na listę uporządkowaną elementu
wybranego, przechowywanego w zmiennej pomocniczej x.
Na początku pętli nr 2 wyznaczamy indeks elementu środkowego partycji i umieszczamy
go w zmiennej i. Następnie sprawdzamy, czy element wybrany, przechowywany w
zmiennej x, jest mniejszy lub równy (dla porządku malejącego większy lub równy) elementowi środkowemu partycji listy
uporządkowanej. Jeśli tak, to pozycja wstawiania znajduje się w pierwszej części partycji - wśród elementów o indeksach od ip do
i. W przeciwnym razie za nową partycję przyjmujemy drugą część - elementy o indeksach od i do ik . Pętlę kontynuujemy do
momentu, aż partycja będzie zawierała tylko jeden element. Wtedy nie ma już wątpliwości i pozycja wstawiania zawsze jest w
zmiennej ip.
Po znalezieniu tej pozycji uruchamia się pętla nr 3. Jej zadaniem jest przesunięcie o 1 pozycję w kierunku początku zbioru
wszystkich elementów listy uporządkowanej poczynając od jej początku aż do pozycji ip. Dzięki tej operacji pozycja ip zostanie
zwolniona i umieszczamy na niej element wybrany. Następnie zmniejszamy indeks j i kontynuujemy pętlę zewnętrzną aż do
posortowania całego zbioru.

Przykład:
Aby lepiej zrozumieć zasadę działania naszego algorytmu, przeanalizujmy prosty przykład wstawiania elementu na
listę uporządkowaną przy pomocy binarnego wyszukiwania pozycji wstawiania. Zbiór ma postać następującą: { 6 3
4 5 7 8 }. Wstawiamy pierwszy element - liczbę 6. Pozostałe elementy tworzą listę uporządkowaną. Na dole
szarymi cyferkami podajemy indeksy elementów:

Zbiór Opis operacji


6 Ze zbioru wybieramy element. Ustalamy indeksy partycji:
3 4 5 7 8
1 2 3 4 5 6 ip = 1, ik = 7
6 Wyznaczamy element środkowy:
3 4 5 7 8
1 2 3 4 5 6 i = (ip + ik) / 2 = (1 + 7) / 2 = 8 / 2 = 4
6 Sprawdzamy, czy 6 jest mniejsze lub równe 5. Nie jest, zatem za nową partycję
3 4 5 7 8 przyjmujemy:
1 2 3 4 5 6 ip = i = 4, ik - pozostaje bez zmian, czyli ik = 7
6 Wyznaczamy nowy element środkowy (pamiętaj, że dzielenie jest
3 4 5 7 8 całkowitoliczbowe):
1 2 3 4 5 6 i = (ip + ik) / 2 = (4 + 7) / 2 = 11 / 2 = 5
6 Sprawdzamy, czy 6 jest mniejsze lub równe 7. Jest, zatem za nową partycję
3 4 5 7 8 przyjmujemy:
1 2 3 4 5 6 ik = i = 5, ip - pozostaje bez zmian, czyli ip = 4
6 Ponieważ różnica ik - ip jest już równa 1, zatem ip zawiera numer pozycji wstawienia
3 4 5 7 8
1 2 3 4 5 6 elementu. Jest to pozycja nr 4 zajmowana obecnie przez liczbę 5.

6 Przesuwamy o jedną pozycję w kierunku początku zbioru elementy listy od jej


3 4 5 7 8
początku do pozycji wstawiania.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 82 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

1 2 3 4 5 6 początku do pozycji wstawiania.

3 4 5 6 7 8 Element wybrany wstawiamy na zwolnione miejsce. Operacja zakończona


1 2 3 4 5 6

Programy
Efekt uruchomienia programu
Binarne sortowanie przez wstawianie
-------------------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
30 36 81 45 71 90 15 57 68 24 39 83 54 1 29 48 69 23 0 77
Po sortowaniu:
0 1 15 23 24 29 30 36 39 45 48 54 57 68 69 71 77 81 83 90

DevPascal
// Binarne Sortowanie Przez Wstawianie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Insertion_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
i,j,x,ip,ik : integer;
begin
writeln(' Binarne sortowanie przez wstawianie ');
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;
// Sortujemy
for j := N - 1 downto 1 do
begin
x := d[j];
ip := j;
ik := N + 1;
while ik - ip > 1 do
begin
i := (ip + ik) div 2;
if x <= d[i] then ik := i else ip := i;
end;
for i := j to ip - 1 do d[i] := d[i + 1];
d[ip] := x;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Binarne Sortowanie Przez Wstawianie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 83 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],i,j,ip,ik,x;
cout << " Binarne sortowanie przez wstawianie\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
for(j = N - 2; j >= 0; j--)
{
x = d[j];
ip = j;
ik = N;
while(ik - ip > 1)
{
i = (ip + ik) / 2;
if(x <= d[i]) ik = i; else ip = i;
}
for(i = j; i < ip; i++) d[i] = d[i + 1];
d[ip] = x;
}
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Binarne Sortowanie Przez Wstawianie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer
Dim i As Integer, j As Integer, x As Integer
Dim ip As Integer, ik As Integer
Print " Binarne sortowanie przez wstawianie "
Print "-------------------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Najpierw wypełniamy tablicę d() liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
For j = N - 1 To 1 Step -1
x = d(j): ip = j: ik = N + 1
While ik - ip > 1
i = Int((ip + ik) / 2)
If x < d(i) Then ik = i Else ip = i
Wend
For i = j To ip - 1: d(i) = d(i + 1): Next
d(ip) = x
Next

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 84 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

' Wyświetlamy wynik sortowania


Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmbinaryinsertionsort">
<h3 style="text-align: center">Binarne Sortowanie Przez Wstawianie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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>
// Binarne Sortowanie Przez Wstawianie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,ip,ik,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
for(j = N - 2; j >= 0; j--)
{
x = d[j];
ip = j;
ik = N;
while(ik - ip > 1)
{
i = Math.floor((ip + ik) / 2);
if(x <= d[i]) ik = i; else ip = i;
}
for(i = j; i < ip; i++) d[i] = d[i + 1];
d[ip] = x;
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Binarne Sortowanie przez Wstawianie


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 85 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu binarnego sortowania przez wstawianie w środowisku opisanym we
wstępie. Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Binarne sortowanie przez wstawianie';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 6; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j,ip,ik : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
for j := n - 1 downto 1 do
begin
x := d[j];
ip := j;
ik := n + 1;
while ik - ip > 1 do
begin
i := (ik + ip) div 2;
if x <= d[i] then ik := i else ip := i;
end;
for i := j to ip - 1 do d[i] := d[i + 1];
d[ip] := x;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 86 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Binarne sortowanie przez wstawianie


------------------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000179 0.005513 0.000184 0.000197 0.003232
2000 0.000453 0.023159 0.000381 0.000385 0.013100
4000 0.000850 0.093319 0.000840 0.000859 0.049430
8000 0.001854 0.370242 0.001848 0.001816 0.186800
16000 0.004150 1.480928 0.004025 0.003942 0.740566
32000 0.008321 6.258433 0.008564 0.008401 3.063959
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 87 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu binarnego sortowania przez
wstawianie wyciągamy następujące wnioski:

Cechy Algorytmu
Binarnego Sortowania Przez Wstawianie
klasa złożoności obliczeniowej optymistyczna O(n log n)

klasa złożoności obliczeniowej typowa O(n2)


klasa złożoności obliczeniowej pesymistyczna O(n2)
Sortowanie w miejscu TAK
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n log n) O(n2) O(n log n) O(n log n) O(n2)
Binarne sortowanie przez wstawianie
tpo << tod tpp ≈ tpk tnp ≈ 1tod
2
1. Góra zrodziła mysz. Algorytm w wersji zoptymalizowanej posiada gorsze własności od wersji podstawowej. Zwróć uwagę, iż
jedyna różnica w klasach złożoności obliczeniowej zachodzi dla przypadku optymistycznego i to na niekorzyść. Teraz
mamy złożoność liniowo-logarytmiczną, która jest gorsza od złożoności liniowej w poprzedniej wersji algorytmu. Wynika z
tego prosty wniosek - nie opłaca się stosować algorytmu binarnego sortowania przez wstawianie. Ewentualne korzyści są
marnowane przez czas zużyty na wykonanie dodatkowych operacji. Wersja podstawowa jest lepsza i szybsza. Być może
zysk wystąpiłby przy sortowaniu zbiorów o bardzo dużej liczbie elementów (wtedy oszczędności na operacjach porównań
zaczęłyby odgrywać istotną rolę w ogólnym czasie sortowania), jednakże w takich przypadkach lepiej zastosować algorytm
sortujący klasy O(n log n), np. Sortowanie Szybkie.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
7 4 8 3 4
Sortowanie przez wstawianie ≈ 3log n ≈ ≈ 3log n ≈ log n ≈
2 5 2 2 5
Binarne sortowanie przez wstawianie
źle źle źle źle źle

2. Wszystkie parametry nowego algorytmu są gorsze od wersji podstawowej. Być może wersja ta okazałaby się szybsza w
sytuacji, gdy operacje porównania pochłaniają dużo więcej czasu w porównaniu z operacjami przesuwania elementów - na
przykład przy sortowaniu tablicy łańcuchów znakowych. Proponuję sprawdzenie tej hipotezy ambitnym czytelnikom
serwisu.

Zadania dla ambitnych


1. Dlaczego zastosowanie wyszukiwania binarnego daje gorsze wyniki w algorytmie sortowania przez wstawianie? Na jakich operacjach
oszczędzamy, a na jakich nie?

Zobacz również na: wersję podstawową

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 88 / 209
Algorytmy Sortujące - Binarne Sortowanie przez Wstawianie 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0011.php 89 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie Shella
Shell Sort
Podrozdziały
Algorytm Programy Badanie algorytmów sortujących
Dobór optymalnych odstępów Program w języku Pascal Podsumowanie
Specyfikacja problemu Program w języku C++ Zadania dla ambitnych
Lista kroków Program w języku Basic
Schemat blokowy Program w języku JavaScript

Algorytm
W latach 50-tych ubiegłego wieku informatyk Donald Shell zauważył, iż algorytm
sortowania przez wstawianie pracuje bardzo efektywnie w przypadku gdy zbiór jest w
dużym stopniu uporządkowany (sprawdź wyniki naszych badań czasów sortowania dla
tego algorytmu). Z kolei algorytm ten pracuje nieefektywnie w zbiorach
nieuporządkowanych, ponieważ elementy są przesuwane w każdym obiegu o jedną
pozycję przy wstawianiu elementu wybranego na listę uporządkowaną.
Pomysł Shella polegał na tym, iż sortowany zbiór dzielimy na podzbiory, których elementy
są odległe od siebie w sortowanym zbiorze o pewien odstęp h. Każdy z tych podzbiorów
sortujemy algorytmem przez wstawianie. Następnie odstęp zmniejszamy. Powoduje to
powstanie nowych podzbiorów (będzie ich już mniej). Sortowanie powtarzamy i znów
zmniejszamy odstęp, aż osiągnie on wartość 1. Wtedy sortujemy już normalnie za pomocą
Instertion Sort. Jednakże z uwagi na wcześniejsze obiegi sortujące mamy ułatwione zadanie, ponieważ zbiór został w dużym
stopniu uporządkowany. Dzięki początkowym dużym odstępom elementy były przesuwane w zbiorze bardziej efektywnie - na duże
odległości. W wyniku otrzymujemy najlepszy pod względem szybkości czasu wykonania algorytm sortujący w klasie O(n2).
Algorytm ten nosi również nazwę algorytmu sortowania przez wstawianie z malejącym odstępem (ang. Diminishing Increment
Sort).
Efektywność algorytmu sortowania metodą Shella zależy w dużym stopniu od ciągu przyjętych odstępów. Pierwotnie Shell
proponował pierwszy odstęp równy połowie liczby elementów w sortowanym zbiorze. Kolejne odstępy otrzymujemy dzieląc odstęp
przez 2 (dzielenie całkowitoliczbowe).

Przykład:
Posortujemy metodą Shella zbiór ośmiu liczb: { 4 2 9 5 6 3 8 1 } w porządku rosnącym. Zbiór posiada osiem
elementów, zatem przyjmiemy na wstępie odstęp h równy 4. Taki odstęp podzieli zbiór na 4 podzbiory, których
elementy będą elementami zbioru wejściowego odległymi od siebie o 4 pozycje. Każdy z otrzymanych podzbiorów
sortujemy algorytmem sortowania przez wstawianie. Ponieważ zbiory te są dwuelementowe, to sortowanie pędzie
polegało na porównaniu pierwszego elementu podzbioru z elementem drugim i ewentualną zamianę ich miejsc, jeśli
będą w niewłaściwym porządku.
Podział, h=4 Sortowanie Wynik
4 2 9 5 6 3 8 1 - Zbiór wejściowy
1 4 6 4 6 4 6
2 2 3 2 3 2 3
3 9 8 8 9 8 9
4 5 1 1 5 1 5
Zbiór wyjściowy - 4 2 8 1 6 3 9 5

Zmniejszamy odstęp h o połowę, więc h = 2. Zbiór podstawowy zostanie podzielony na dwa podzbiory. Każdy z
tych podzbiorów sortujemy przez wstawianie:

Podział, h=2 Sortowanie Wynik


4 2 8 1 6 3 9 5 - Zbiór wejściowy
1 4 8 6 9 4 6 8 9 4 6 8 9
2 2 1 3 5 1 2 3 5 1 2 3 5
Zbiór wyjściowy - 4 1 6 2 8 3 9 5

Zmniejszamy odstęp h o połowę, h = 1. Taki odstęp nie dzieli zbioru wejściowego na podzbiory, więc teraz będzie
sortowany przez wstawianie cały zbiór. Jednak algorytm sortujący ma ułatwioną pracę, ponieważ dzięki poprzednim
dwóm obiegom zbiór został częściowo uporządkowany - elementy małe zbliżyły się do początku zbioru, a elementy

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 90 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

duże do końca.

Podział, h=1 Sortowanie Wynik


4 1 6 2 8 3 9 5 - Zbiór wejściowy
1 4 1 6 2 8 3 9 5 1 2 3 4 5 6 8 9 1 2 3 4 5 6 8 9
Zbiór wyjściowy - 1 2 3 4 5 6 8 9

Dobór optymalnych odstępów


Kluczowym elementem wpływającym na efektywność sortowania metodą Shella jest właściwy dobór ciągu
odstępów. Okazuje się, iż ciąg zaproponowany przez twórcę algorytmu jest jednym z najgorszych, ponieważ w
kolejnych podzbiorach uczestniczą wielokrotnie te same elementy (możesz to prosto sprawdzić w podanym powyżej
przykładzie).
Dotąd problem optymalnych odstępów w algorytmie sortowania metodą Shella nie został rozwiązany matematycznie,
ponieważ w ogólnym przypadku jest niezwykle trudny. Wielu badaczy proponowało na wybór tych odstępów różne
ciągi liczbowe otrzymując lepsze lub gorsze rezultaty.
Na przykład profesor Donald Knuth (autor "Sztuki Programowania Komputerów" - "The Art of Computer
prof. Donald Knuth Programming") zbadał bardzo dokładnie algorytm sortowania metodą Shella i doszedł do wniosku, iż dobry
ciąg odstępów dla n elementowego zbioru można wyznaczyć następująco:
Przyjmujemy h1 = 1
obliczamy hs = 3hs-1 + 1 aż do momentu gdy hs n
Ostatecznie h = [hs : 9]

Przykład:
Obliczmy pierwszy odstęp dla zbioru o n = 200 elementach:

h1 = 1
h2 = 3h1 + 1 = 3 + 1 = 4 - mniejsze od 200, kontynuujemy
h3 = 3h2 + 1 = 12 + 1 = 13 - kontynuujemy
h4 = 3h3 + 1 = 39 + 1 = 40 - kontynuujemy
h5 = 3h4 + 1 = 120 + 1 = 121 - kontynuujemy
h6 = 3h5 + 1 = 363 + 1 = 364 - stop, ponieważ jest większe od 200
h = [h6 : 9] = [364 : 9] = [40 4/9] = 40 (zwróć uwagę, iż jest to zawsze element wcześniejszy o dwie
pozycje, czyli h4)

Kolejne odstępy obliczamy dzieląc całkowitoliczbowo bieżący odstęp przez 3. Taki właśnie sposób wyliczania
odstępów przyjmiemy w naszym algorytmie.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - zbiór n-elementowy, który będzie sortowany. Elementy zbioru mają indeksy od 1 do n.
Dane wyjściowe
d[ ] - posortowany zbiór n-elementowy. Elementy zbioru mają indeksy od 1 do n.

Zmienne pomocnicze
i - indeks elementu listy uporządkowanej, i Î N
j - zmienna sterująca pętli, j Î N
h - odstęp pomiędzy kolejnymi elementami podzbiorów, h Î N
x - zawiera wybrany ze zbioru element

Lista kroków
K01: h←1
K02: Powtarzaj h ← 3h + 1, aż h ≥ n
K03: h ← h div 9
K04: Jeśli h = 0, to h ← 1
K05: Dopóki h > 0: wykonuj K06...K10
K06: Dla j = n - h, n - h - 1, ..., 1: wykonuj K07...K09
K07: x ← d[j]; i ← j + h
K08: Dopóki (i ≤ n) i (x > d[i]): wykonuj d[i - h] ← d[i]; i ← i + h
K09: d[i - h] ← x

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 91 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

K10: h ← h div 3
K11: Zakończ

Schemat blokowy
Algorytm sortowania metodą Shella jest ulepszonym algorytmem
sortowania przez wstawianie. Aby się o tym przekonać, wystarczy
spojrzeć na schemat blokowy. Kolorem szarym zaznaczyliśmy na nim
bloki, które dokładnie odpowiadają algorytmowi sortowania przez
wstawianie. Jedyną modyfikacją jest wprowadzenie odstępu h zamiast
liczby 1.
Na początku algorytmu wyznaczamy wartość początkowego odstępu h.
Wykorzystujemy tu sugestie prof. Donalda Knutha.
Po wyznaczeniu h rozpoczynamy pętlę warunkową nr 1. Pętla ta jest
wykonywana dotąd, aż odstęp h przyjmie wartość 0. Wtedy kończymy
algorytm, zbiór będzie posortowany.
Wewnątrz pętli nr 1 umieszczony jest opisany wcześniej algorytm
sortowania przez wstawianie, który dokonuje sortowania elementów
poszczególnych podzbiorów wyznaczonych przez odstęp h. Po
zakończeniu sortowania podzbiorów odstęp h jest zmniejszany i
następuje powrót na początek pętli warunkowej nr 1.

Uwaga techniczna:
Każdy obieg pętli nr 2 sortuje przemiennie jeden element z kolejnych podzbiorów. Najpierw będą to elementy
przedostatnie w kolejnych podzbiorach wyznaczonych odstępem h, później wcześniejsze i wcześniejsze. Takie
podejście znacząco upraszcza algorytm sortowania.

Programy
Efekt uruchomienia programu
Sortowanie metoda Shella
--------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
65 89 49 99 57 2 35 2 86 48 90 54 89 20 32 6 52 20 40 17
Po sortowaniu:
2 2 6 17 20 20 32 35 40 48 49 52 54 57 65 86 89 89 90 99

DevPascal
// Sortowanie Metodą Shella
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Shell_Sort;
const N = 20; // Liczebność zbioru.
var
d : array[1..N] of integer;
// Program główny
//---------------
var
h,i,j,x : integer;
begin
writeln(' Sortowanie metoda Shella ');
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;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 92 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

// Wyznaczamy wartość początkowego przesunięcia


h := 1;
repeat
h := 3 * h + 1;
until h >= N;
h := (h div 9);
if h = 0 then h := 1; // istotne dla małych N, dla większych można pominąć!
// Sortujemy
while h > 0 do
begin
for j := N - h downto 1 do
begin
x := d[j];
i := j + h;
while (i <= N) and (x > d[i]) do
begin
d[i - h] := d[i];
inc(i, h);
end;
d[i - h] := x;
end;
h := h div 3;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie metodą Shella
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
// Program główny
//---------------
int main()
{
int d[N],h,i,j,x;
cout << " Sortowanie metoda Shella\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Wyznaczamy wartość początkowego przesunięcia
for(h = 1; h < N; h = 3 * h + 1);
h /= 9;
if(!h) h++; // istotne dla małych N, dla większych można pominąć!
// Sortujemy
while(h)
{
for(j = N - h - 1; j >= 0; j--)
{
x = d[j];
i = j + h;
while((i < N) && (x > d[i]))
{
d[i - h] = d[i];
i += h;
}
d[i - h] = x;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 93 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

}
h /= 3;
}
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Metodą Shella
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim d(1 To N) As Integer
Dim h As Integer, i As Integer, j As Integer, x As Integer
Print " Sortowanie metoda Shella "
Print "--------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Najpierw wypełniamy tablicę d() liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Wyznaczamy wartość początkowego przesunięcia
h = 1
Do
h = 3 * h + 1
Loop Until h >= N
h = Int(h / 9)
If h = 0 Then h = 1 ' istotne dla małych N, dla większych można pominąć!
' Sortujemy
While h > 0
For j = N - h To 1 Step -1
x = d(j)
i = j + h
While (i <= N) And (x > d(i))
d(i - h) = d(i)
i = i + h
Wend
d(i - h) = x
Next
h = Int(h / 3)
Wend
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmshellsort">
<h3 style="text-align: center">Sortowanie Metodą Shella</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Sortuj" name="B1">
</p>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 94 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03
</p>
<p id="t_out" style="TEXT-ALIGN: center">...</p>
</form>
<script language=javascript>
// Sortowanie Metodą Shella
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
function main()
{
var d = new Array(N);
var i,j,ip,ik,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Wyznaczamy początkowe przesunięcie
for(h = 1; h < N; h = 3 * h + 1);
h = Math.floor(h / 9);
if(!h) h++; // istotne dla małych N, dla większych można pominąć!
// Sortujemy
while(h)
{
for(j = N - h - 1; j >= 0; j--)
{
x = d[j];
i = j + h;
while((i < N) && (x > d[i]))
{
d[i - h] = d[i];
i += h;
}
d[i - h] = x;
}
h = Math.floor(h / 3);
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Metodą Shella


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania metodą Shella w środowisku opisanym we wstępie.
Ponieważ algorytm jest bardzo szybki, zdecydowaliśmy się przetestować go na pełnym zakresie danych od 1000 do 128000
elementów. Program testujący jest następujący: DLA
GENIUSZA

DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 95 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie metodą Shella';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
var
i,j,h : integer;
x : real;
begin
QueryPerformanceCounter(addr(qpc1));
h := 1;
repeat
h := 3 * h + 1;
until h >= n;
h := (h div 9);
while(h > 0) do
begin
for j := n - h downto 1 do
begin
x := d[j];
i := j + h;
while (i <= n) and (x > d[i]) do
begin
d[i - h] := d[i];
i += h;
end;
d[i - h] := x;
end;
h := h div 3;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 96 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

// z przypadkowym elementem na początku - średnia z 10 obiegów


tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie metodą Shella


-----------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000296 0.000509 0.000317 0.000320 0.000733
2000 0.000703 0.001106 0.000747 0.000781 0.001714
4000 0.001600 0.002938 0.001697 0.001707 0.005099
8000 0.003368 0.006315 0.003527 0.003490 0.008908
16000 0.007572 0.012641 0.009127 0.009796 0.020476
32000 0.016916 0.026260 0.017641 0.017699 0.046787
64000 0.034763 0.056447 0.036213 0.036643 0.104610
128000 0.076624 0.123158 0.080277 0.080089 0.236036
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu binarnego sortowania przez
wstawianie wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Metodą Shella


klasa złożoności obliczeniowej optymistyczna O(n1,14)
klasa złożoności obliczeniowej typowa

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 97 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

klasa złożoności obliczeniowej typowa


O(n1,15)
klasa złożoności obliczeniowej pesymistyczna
Sortowanie w miejscu TAK
Stabilność NIE

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp

O(n1,14) O(n1,14) O(n1,14) O(n1,14) O(n1,14)


Sortowanie metodą Shella z odstępami Knutha
tpo ≈ 3tod tpp ≈ tpk tnp ≈ 2tod
5

1. Wszystkie badane czasy sortowania są dosyć dobrze proporcjonalne do O(n1,12...1,16). Przyjęliśmy wartość średnią
O(n1,14) - jest to oszacowanie przybliżone, które należy brać z pewną rezerwą.
2. Czas sortowania zbioru uporządkowanego odwrotnie jest krótszy od czasu sortowania zbioru nieuporządkowanego. Wynika
stąd, iż nie jest to przypadek pesymistyczny dla tego algorytmu.
3. Zbiory w znacznym stopniu uporządkowane są sortowane dużo szybciej od zbiorów nieuporządkowanych.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

Sortowanie przez wstawianie ≈ 1n-0,14 ≈ 1 n0,86 ≈ 2n-0,14 ≈ 1n-0,14 ≈ 1 n0,86


Sortowanie metodą Shella 3 37 5 3 142
źle dobrze źle źle dobrze

4. Z oszacowań wzrostu prędkości wynika, iż algorytm sortowania metodą Shella jest bezkonkurencyjny w klasie
O(n2) algorytmów sortujących przy sortowaniu zbiorów nieuporządkowanych i zbiorów posortowanych odwrotnie, czyli w
przypadku ogólnym. Jednakże przy sortowaniu zbiorów w dużym stopniu uporządkowanych lepszym okazuje się
poprzednio opisany algorytm sortowania przez wstawianie. Oszacowania wyznaczonych wzrostów prędkości nie należy
traktować jako wzorów matematycznych - to tylko próba dopasowania pewnych funkcji, które w przyszłości należy
dokładniej zweryfikować.

Zadania dla ambitnych


1. Dlaczego algorytm sortowania metodą Shella nie jest stabilny jeśli chodzi o zachowanie kolejności elementów równych w sortowanym
zbiorze?
2. Wyjaśnij, dlaczego algorytm sortowania przez wstawianie szybciej sortuje zbiory uporządkowane od algorytmu sortowania metodą Shella.
3. Porównaj wzrost prędkości algorytmu sortowania metodą Shella w stosunku do algorytmów sortowania bąbelkowego i sortowania przez
wybór. Wyciągnij odpowiednie wnioski.

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 98 / 209
Algorytmy Sortujące - Sortowanie metodą Shella 2014-10-03

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0012.php 99 / 209
Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie przez scalanie


Merge Sort
Podrozdziały
Algorytm Programy Badanie algorytmów sortujących
Rekurencyjne obliczanie silni Program w języku Pascal Podsumowanie
Scalanie zbiorów uporządkowanych Program w języku C++ Zadania dla ambitnych
Algorytm scalania Program w języku Basic
Specyfikacja algorytmu scalania Program w języku JavaScript
Lista kroków algorytmu scalania
Schemat blokowy algorytmu scalania
Specyfikacja algorytmu sortującego
Lista kroków algorytmu sortującego
Schemat blokowy algorytmu sortującego

Algorytm
Poczynając od tego rozdziału przechodzimy do opisu algorytmów szybkich, tzn. takich, które posiadają klasę czasowej
złożoności obliczeniowej równą O(n log n) lub nawet lepszą.
W informatyce zwykle obowiązuje zasada, iż prosty algorytm posiada dużą złożoność obliczeniową, natomiast algorytm
zaawansowany posiada małą złożoność obliczeniową, ponieważ wykorzystuje on pewne własności, dzięki którym szybciej
dochodzi do rozwiązania.
Wiele dobrych algorytmów sortujących korzysta z rekurencji, która powstaje wtedy, gdy do rozwiązania problemu algorytm
wykorzystuje samego siebie ze zmienionym zestawem danych.
Przykład:
Jako przykład może posłużyć rekurencyjne obliczanie silni. Silnię liczby n należącej do zbioru liczb naturalnych
definiujemy następująco:
n! = 1 × 2 × 3 × ... × (n - 1) × n
Na przykład: 5! = 1 × 2 × 3 × 4 × 5 = 120

Rekurencyjne obliczanie silni


Specyfikacja algorytmu
Dane wejściowe
n - liczba, której silnie liczymy na danym poziomie rekurencyjnym, n Î N
Dane wyjściowe
Wartość silni n!

Lista kroków
K01: Jeśli n < 2, silnia(n) ← 1 i zakończ
K02: silnia(n) ← n × silnia(n - 1) i zakończ

Przykładowy program w języku Pascal


// Rekurencyjne obliczanie silni
//------------------------------
// (C)2012 I LO w Tarnowie
// I LO w Tarnowie
//------------------------------
program silnia_rek;
function silnia(n : integer) : extended;
begin
if n < 2 then silnia := 1 else silnia := n * silnia(n - 1);
end;
var
n : cardinal;
begin
writeln('Program oblicza rekurencyjnie silnie z liczby n');
writeln('------------------------------------------------------');
writeln('(C)2005 mgr Jerzy Walaszek I LO w Tarnowie');
writeln;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 100 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

write('Podaj n = '); readln(n);


writeln;
writeln(n,'! = ',silnia(n):0:0);
writeln;
write('Nacisnij Enter...'); readln;
end.

Dzięki rekurencji funkcja wyliczająca wartość silni staje się niezwykle prosta. Najpierw sprawdzamy warunek zakończenia
rekurencji, tzn. sytuację, gdy wynik dla otrzymanego zestawu danych jest oczywisty. W przypadku silni sytuacja taka wystąpi dla
n < 2 - silnia ma wartość 1. Jeśli warunek zakończania rekurencji nie wystąpi, to wartość wyznaczamy za pomocą
rekurencyjnego wywołania obliczania silni dla argumentu zmniejszonego o 1. Wynik tego wywołania mnożymy przez n i zwracamy
jako wartość silni dla n.

Wynaleziony w 1945 roku przez Johna von Neumanna algorytm sortowania przez scalanie jest algorytmem rekurencyjnym.
Wykorzystuje zasadę dziel i zwyciężaj, która polega na podziale zadania głównego na zadania mniejsze dotąd, aż rozwiązanie
stanie się oczywiste. Algorytm sortujący dzieli porządkowany zbiór na kolejne połowy dopóki taki podział jest możliwy (tzn.
podzbiór zawiera co najmniej dwa elementy). Następnie uzyskane w ten sposób części zbioru rekurencyjnie sortuje tym samym
algorytmem. Posortowane części łączy ze sobą za pomocą scalania tak, aby wynikowy zbiór był posortowany.

Scalanie zbiorów uporządkowanych


Podstawową operacją algorytmu jest scalanie dwóch zbiorów uporządkowanych w jeden zbiór również uporządkowany. Operację
scalania realizujemy wykorzystując pomocniczy zbiór, w którym będziemy tymczasowo odkładać scalane elementy dwóch
zbiorów. Ogólna zasada jest następująca:

1. Przygotuj pusty zbiór tymczasowy


2. Dopóki żaden ze scalanych zbiorów nie jest pusty, porównuj ze sobą pierwsze elementy każdego z nich
i w zbiorze tymczasowym umieszczaj mniejszy z elementów usuwając go jednocześnie ze scalanego
zbioru.
3. W zbiorze tymczasowym umieść zawartość tego scalanego zbioru, który zawiera jeszcze elementy.
4. Zawartość zbioru tymczasowego przepisz do zbioru wynikowego i zakończ algorytm.

Przykład:
Połączmy za pomocą opisanego algorytmu dwa uporządkowane zbiory: { 1 3 6 7 9 } z { 2 3 4 6 8 }

Scalane Zbiór
Opis wykonywanych działań
zbiory tymczasowy
Porównujemy ze sobą najmniejsze elementy scalanych
[1] 3 6 7 9 zbiorów. Ponieważ zbiory te są już uporządkowane, to
2 3 4 6 8 najmniejszymi elementami będą zawsze ich pierwsze
elementy.
W zbiorze tymczasowym umieszczamy mniejszy
3 6 7 9 [1] element, w tym przypadku będzie to liczba 1.
2 3 4 6 8 Jednocześnie element ten zostaje usunięty z pierwszego
zbioru
3 6 7 9 1 Porównujemy kolejne dwa elementy i mniejszy
[2] 3 4 6 8 umieszczamy w zbiorze tymczasowym.
Następne porównanie i w zbiorze tymczasowym
[3] 6 7 9 1[2] umieszczamy liczbę 3. Ponieważ są to elementy równe,
3 4 6 8 to nie ma znaczenia, z którego zbioru weźmiemy element
3.
6 7 9 1 2[3] Teraz do zbioru tymczasowego trafi drugie 3.
[3] 4 6 8
6 7 9 1 2 3[3] W zbiorze tymczasowym umieszczamy mniejszy z
[4] 6 8 porównywanych elementów, czyli liczbę 4.
[6] 7 9 1 2 3 3[4] Porównywane elementy są równe, zatem w zbiorze
6 8 tymczasowym umieszczamy dowolny z nich.
7 9
[6] 8
1 2 3 3 4[6] Teraz drugą liczbę 6.

[7] 9
8
1 2 3 3 4 6[6] W zbiorze tymczasowym umieszczamy liczbę 7

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 101 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

9
[8]
1 2 3 3 4 6 6[7] Teraz 8

Drugi zbiór jest pusty. Od tego momentu już nie


[9] 1 2 3 3 4 6 6 7[8] porównujemy, lecz wprowadzamy do zbioru
t y mc z as owego wszystkie pozostałe elementy
pierwszego zbioru, w tym przypadku będzie to liczba 9.
Koniec scalania. Zbiór tymczasowy zawiera wszystkie
1 2 3 3 4 6 6 7 8[9] elementy scalanych zbiorów i jest uporządkowany.
Możemy w dalszej kolejności przepisać jego zawartość
do zbioru docelowego.

Z podanego przykładu możemy wyciągnąć wniosek, iż operacja scalania dwóch uporządkowanych zbiorów jest dosyć prosta.
Diabeł jak zwykle tkwi w szczegółach.

Algorytm scalania dwóch zbiorów


Przed przystąpieniem do wyjaśniania sposobu łączenia dwóch zbiorów uporządkowanych w jeden zbiór również
uporządkowany musimy zastanowić się nad sposobem reprezentacji danych. Przyjmijmy, iż elementy zbioru będą
przechowywane w jednej tablicy, którą oznaczymy literką d. Każdy element w tej tablicy będzie posiadał swój numer, czyli indeks
z zakresu od 1 do n.
Kolejnym zagadnieniem jest sposób reprezentacji scalanych zbiorów. W przypadku algorytmu sortowania przez scalanie
zawsze będą to dwie przyległe połówki zbioru, który został przez ten algorytm podzielony. Co więcej, wynik scalenia ma być
umieszczony z powrotem w tym samym zbiorze.

Przykład:
Prześledźmy prosty przykład. Mamy posortować zbiór o postaci: { 6 5 4 1 3 7 9 2 }

Sortowany zbiór
Opis wykonywanych operacji
d[1] d[2] d[3] d[4] d[5] d[6] d[7] d[8]
6 5 4 1 3 7 9 2 Zbiór wyjściowy.
6 5 4 1 3 7 9 2 Pierwszy podział.
6 5 4 1 3 7 9 2 Drugi podział
6 5 4 1 3 7 9 2 Trzeci podział.
5 6 1 4 3 7 2 9 Pierwsze scalanie.
1 4 5 6 2 3 7 9 Drugie scalanie.
1 2 3 4 5 6 7 9 Trzecie scalanie. Koniec.

Ponieważ w opisywanym tutaj algorytmie sortującym scalane podzbiory są przyległymi do siebie częściami innego zbioru, zatem
logiczne będzie użycie do ich definicji indeksów wybranych elementów tych podzbiorów:

ip - indeks pierwszego elementu w młodszym podzbiorze


is - indeks pierwszego elementu w starszym podzbiorze
ik - indeks ostatniego elementu w starszym podzbiorze

Przez podzbiór młodszy rozumiemy podzbiór zawierający elementy o indeksach mniejszych niż indeksy elementów w podzbiorze
starszym.

ip ... is ... ik
pozostała część zbioru pozostała część zbioru
młodszy podzbiór starszy podzbiór

Indeks końcowego elementu młodszej połówki zbioru z łatwością wyliczamy - będzie on o 1 mniejszy od indeksu pierwszego
elementu starszej połówki.

Przykład:

Po pierwszym podziale prezentowanego powyżej Po kolejnym podziale połówek otrzymujemy 4 ćwiartki


zbioru otrzymujemy następujące wartości indeksów: dwuelementowe. Wartości indeksów będą następujące:
Młodsza Starsza Młodsza połówka Starsza połówka
połówka połówka
Młodsza Starsza Młodsza Starsza
ip = 1 is = 5 ćwiartka ćwiartka ćwiartka ćwiartka

ik = 8 ip = 1 is = 3 ip = 5 is = 7
ik = 4 ik = 8

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 102 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

Specyfikacja algorytmu scalania


Scalaj(ip, is, ik )
Dane wejściowe
d[ ] - scalany zbiór
ip - indeks pierwszego elementu w młodszym podzbiorze, ip Î N
is - indeks pierwszego elementu w starszym podzbiorze, is Î N
ik - indeks ostatniego elementu w starszym podzbiorze, ik Î N

Dane wyjściowe
d[ ] - scalony zbiór
Zmienne pomocnicze
p[ ] - zbiór pomocniczy, który zawiera tyle samo elementów, co zbiór d[ ].
i1 - indeks elementów w młodszej połówce zbioru d[ ], i1 Î N
i2 - indeks elementów w starszej połówce zbioru d[ ], i2 Î N
i - indeks elementów w zbiorze pomocniczym p[ ], i Î N

Lista kroków algorytmu scalania


K01: i1 ← ip; i2 ← is; i ← ip
K02: Dla i = ip, ip + 1, ..., ik: wykonuj
jeśli (i1 = is) (i2 ≤ ik i d[i1] > d[i2]), to
p[i] ← d[i2]; i2 ← i2 + 1
inaczej
p[i] ← d[i1]; i1 ← i1 + 1
K03: Dla i = ip, ip + 1,...,ik: d[i] ← p[i]
K04: Zakończ

Schemat blokowy algorytmu scalania


Operacja scalania dwóch podzbiorów wymaga dodatkowej pamięci o
rozmiarze równym sumie rozmiarów scalanych podzbiorów. Dla prostoty na
potrzeby naszego algorytmu zarezerwujemy tablicę p o rozmiarze równym
rozmiarowi zbioru d[ ]. W tablicy p algorytm będzie tworzył zbiór
tymczasowy, który po zakończeniu scalania zostanie przepisany do zbioru
d[ ] w miejsce dwóch scalanych podzbiorów.
Parametrami wejściowymi do algorytmu są indeksy ip, is oraz ik , które
jednoznacznie definiują położenie dwóch podzbiorów do scalenia w obrębie
tablicy d[ ]. Elementy tych podzbiorów będą indeksowane za pomocą
zmiennych i1 (młodszy podzbiór od pozycji ip do is - 1) oraz i2 (starszy
podzbiór od pozycji is do ik ). Na początku algorytmu przypisujemy tym
zmiennym indeksy pierwszych elementów w każdym podzbiorze.
Zmienna i będzie zawierała indeksy elementów wstawianych do tablicy p[ ].
Dla ułatwienia indeksy te przebiegają wartości od ip do ik , co odpowiada
obszarowi tablicy d[ ] zajętemu przez dwa scalane podzbiory. Na początku do
zmiennej i wprowadzamy indeks pierwszego elementu w tym obszarze, czyli
ip.
Wewnątrz pętli sprawdzamy, czy indeksy i1 i i2 wskazują elementy
podzbiorów. Jeśli któryś z nich wyszedł poza dopuszczalny zakres, to dany
podzbiór jest wyczerpany - w takim przypadku do tablicy p przepisujemy
elementy drugiego podzbioru.
Jeśli żaden z podzbiorów nie jest wyczerpany, porównujemy kolejne elementy
z tych podzbiorów wg indeksów i1 i i2. Do tablicy p[ ] zapisujemy zawsze mniejszy z porównywanych elementów. Zapewnia to
uporządkowanie elementów w tworzonym zbiorze wynikowym. Po zapisie elementu w tablicy p[ ], odpowiedni indeks i1 lub i2 jest
zwiększany o 1. Zwiększany jest również indeks i, aby kolejny zapisywany element w tablicy p[ ] trafił na następne wolne
miejsce. Pętla jest kontynuowana aż do zapełnienia w tablicy p[ ] obszaru o indeksach od ip do ik .
Wtedy przechodzimy do końcowej pętli, która przepisuje ten obszar z tablicy p[ ] do tablicy wynikowej d[ ]. Scalane zbiory
zostają zapisane zbiorem wynikowym, który jest posortowany rosnąco.

Specyfikacja algorytmu sortującego


Sortuj_przez_scalanie(ip, ik )

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 103 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

Dane wejściowe
d[ ] - sortowany zbiór
ip - indeks pierwszego elementu w młodszym podzbiorze, ip Î N
ik - indeks ostatniego elementu w starszym podzbiorze, ik Î N

Dane wyjściowe
d[ ] - posortowany zbiór

Zmienne pomocnicze
is - indeks pierwszego elementu w starszym podzbiorze, is Î N

Lista kroków algorytmu sortującego


K01: is ← (ip + ik + 1) div 2
K02: Jeśli is - ip > 1, to Sortuj_przez_scalanie(ip, is - 1)
K03: Jeśli ik - is > 0, to Sortuj_przez_scalanie(is, ik)
K04: Scalaj(ip, is, ik)
K05: Zakończ

Schemat blokowy algorytmu sortującego


Algorytm sortowania przez scalanie jest algorytmem rekurencyjnym. Wywołuje się go z
zadanymi wartościami indeksów ip oraz ik . Przy pierwszym wywołaniu indeksy te powinny
objąć cały zbiór d, zatem ip = 1, a ik = n.
Najpierw algorytm wyznacza indeks is, który wykorzystywany jest do podziału zbioru na
dwie połówki:
- młodszą o indeksach elementów od ip do is - 1
- starszą o indeksach elementów od is do ik
Następnie sprawdzamy, czy dana połówka zbioru zawiera więcej niż jeden element. Jeśli
tak, to rekurencyjnie sortujemy ją tym samym algorytmem.
Po posortowaniu obu połówek zbioru scalamy je za pomocą opisanej wcześniej procedury
scalania podzbiorów uporządkowanych i kończymy algorytm. Zbiór jest posortowany.
W przykładowych programach procedurę scalania umieściliśmy bezpośrednio w kodzie
algorytmu sortującego, aby zaoszczędzić na wywoływaniu.

Programy
Efekt uruchomienia programu
Sortowanie przez scalanie
---------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
37 91 80 5 38 97 6 40 31 96 97 76 85 25 3 69 11 43 34 53
Po sortowaniu:
3 5 6 11 25 31 34 37 38 40 43 53 69 76 80 85 91 96 97 97

DevPascal
// Sortowanie Przez Scalanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program Merge_Sort;
const N = 20; // Liczebność zbioru.
var
d,p : array[1..N] of integer;
// Procedura sortująca

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 104 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

//--------------------
procedure MergeSort(i_p,i_k : integer);
var
i_s,i1,i2,i : integer;
begin
i_s := (i_p + i_k + 1) div 2;
if i_s - i_p > 1 then MergeSort(i_p, i_s - 1);
if i_k - i_s > 0 then MergeSort(i_s, i_k);
i1 := i_p; i2 := i_s;
for i := i_p to i_k do
if (i1 = i_s) or ((i2 <= i_k) and (d[i1] > d[i2])) then
begin
p[i] := d[i2]; inc(i2);
end
else
begin
p[i] := d[i1]; inc(i1);
end;
for i := i_p to i_k do d[i] := p[i];
end;
// Program główny
//---------------
var
i : integer;
begin
writeln(' Sortowanie przez scalanie ');
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;
// Sortujemy
MergeSort(1,N);
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie przez scalanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 20; // Liczebność zbioru.
int d[N],p[N];
// Procedura sortująca
//--------------------
void MergeSort(int i_p, int i_k)
{
int i_s,i1,i2,i;
i_s = (i_p + i_k + 1) / 2;
if(i_s - i_p > 1) MergeSort(i_p, i_s - 1);
if(i_k - i_s > 0) MergeSort(i_s, i_k);
i1 = i_p; i2 = i_s;
for(i = i_p; i <= i_k; i++)
p[i] = ((i1 == i_s) || ((i2 <= i_k) && (d[i1] > d[i2]))) ? d[i2++] : d[i1++];
for(i = i_p; i <= i_k; i++) d[i] = p[i];
}
// Program główny
//---------------
int main()
{

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 105 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

int i;
cout << " Sortowanie przez scalanie\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ść
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = rand() % 100;
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// Sortujemy
MergeSort(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;
return 0;
}

Free Basic
' Sortowanie Przez Scalanie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 20 ' Liczebność zbioru.
Dim Shared d(1 To N) As Integer
Dim Shared p(1 To N) As Integer
Declare Sub MergeSort(Byval i_p As Integer, Byval i_k As Integer)
Dim i As Integer
Print " Sortowanie przez scalanie "
Print "---------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Najpierw wypełniamy tablicę d() liczbami pseudolosowymi
' a następnie wyświetlamy jej zawartość
Randomize Timer
For i = 1 To N: d(i) = Int(Rnd * 100): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' Sortujemy
MergeSort 1, N
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End
' Procedura sortująca
'--------------------
Public Sub MergeSort(Byval i_p As Integer, Byval i_k As Integer)
Dim i_s As Integer, i1 As Integer, i2 As Integer, i As Integer
i_s = Int((i_p + i_k + 1) / 2)
If i_s - i_p > 1 Then MergeSort i_p, i_s - 1
If i_k - i_s > 0 Then MergeSort i_s, i_k
i1 = i_p: i2 = i_s
For i = i_p To i_k
If (i1 = i_s) Or ((i2 <= i_k) And (d(i1) > d(i2))) Then
p(i) = d(i2): i2 = i2 + 1
Else
p(i) = d(i1): i1 = i1 + 1
End If
Next
For i = i_p To i_k: d(i) = p(i): Next
End Sub

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 106 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

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="frmmergesort">
<h3 style="text-align: center">Sortowanie Przez Scalanie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Przez Scalanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 20; // Liczebność zbioru.
var d = new Array(N);
var p = new Array(N);
// Procedura sortująca
//--------------------
function MergeSort(i_p, i_k)
{
var i_s,i1,i2,i;
i_s = Math.floor((i_p + i_k + 1) / 2);
if(i_s - i_p > 1) MergeSort(i_p, i_s - 1);
if(i_k - i_s > 0) MergeSort(i_s, i_k);
i1 = i_p; i2 = i_s;
for(i = i_p; i <= i_k; i++)
p[i] = ((i1 == i_s) || ((i2 <= i_k) && (d[i1] > d[i2]))) ? d[i2++] : d[i1++];
for(i = i_p; i <= i_k; i++) d[i] = p[i];
}
function main()
{
var i,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
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] + " ";
t += "<BR><BR>";
// Sortujemy
MergeSort(0,N-1);
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Przez Scalanie


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 107 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania przez scalanie w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie przez scalanie';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d,p : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
procedure MergeSort(i_p,i_k : integer);
var
i_s,i1,i2,i : integer;
begin
i_s := (i_p + i_k + 1) div 2;
if i_s - i_p > 1 then MergeSort(i_p, i_s - 1);
if i_k - i_s > 0 then MergeSort(i_s, i_k);
i1 := i_p; i2 := i_s;
for i := i_p to i_k do
if (i1 = i_s) or ((i2 <= i_k) and (d[i1] > d[i2])) then
begin
p[i] := d[i2]; inc(i2);
end
else
begin
p[i] := d[i1]; inc(i1);
end;
for i := i_p to i_k do d[i] := p[i];
end;
function Sort : extended;
begin
QueryPerformanceCounter(addr(qpc1));
MergeSort(1,n);
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 108 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program


Nazwa: Sortowanie przez scalanie
-----------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000274 0.000259 0.000263 0.000262 0.000391
2000 0.000560 0.000591 0.000584 0.000568 0.000840
4000 0.001261 0.001262 0.001248 0.001216 0.002238
8000 0.002701 0.006158 0.003400 0.002767 0.003980
16000 0.006094 0.005883 0.005942 0.005916 0.008612
32000 0.013152 0.012807 0.012899 0.012949 0.018664
64000 0.027800 0.026875 0.027786 0.027917 0.039992
128000 0.060092 0.057705 0.058853 0.059038 0.084633
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 109 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania przez scalanie
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Przez Scalanie


klasa złożoności obliczeniowej optymistyczna
klasa złożoności obliczeniowej typowa O(n log n)
klasa złożoności obliczeniowej pesymistyczna
Sortowanie w miejscu NIE
Stabilność TAK

Klasy złożoności obliczeniowej szacujemy następująco:

optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n log n) O(n log n) O(n log n) O(n log n) O(n log n)
Sortowanie przez scalanie
tpo ≈ tod tpp ≈ tpk tnp ≈ 2tod
3
1. Wszystkie badane czasy są proporcjonalne do nlog2n, zatem wnioskujemy, iż algorytm sortowania przez scalanie posiada
klasę czasowej złożoności obliczeniowej równą O(n log n).
2. Najdłużej trwa sortowanie zbioru nieuporządkowanego. Jednakże badane czasy nie różnią się wiele pomiędzy sobą, co
sugeruje, iż algorytm nie jest specjalnie czuły na rozkład danych wejściowych.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
6 4 4 5
Sortowanie metodą Shella ≈5 ≈2 ≈3 ≈3 ≈2
Sortowanie przez scalanie
dobrze dobrze dobrze dobrze dobrze

3. Porównanie czasów działania algorytmów sortowania metodą Shella oraz sortowania przez scalanie doprowadza do
wniosku, iż ten drugi algorytm jest szybszy. W przypadku ogólnym zbiór zostanie posortowany 2,5 razy szybciej
(dokładniejsza analiza na pewno pokaże, iż nie są to stosunki stałe, lecz zależą on liczby elementów w sortowanym
zbiorze i rosną wraz ze wzrostem n). W przypadku zbioru posortowanego odwrotnie zysk jest dwukrotny. Szybkość
działania jest jednak okupiona większym zapotrzebowaniem na pamięć - złożoność pamięciowa jest klasy O(n), gdyż dla n
elementowego zbioru musimy dodatkowo zarezerwować tablicę n elementową dla zbioru będącego wynikiem scalania.

Zadania dla ambitnych


1. Porównaj wzrost prędkości działania algorytmu sortowania przez scalanie w stosunku do algorytmu sortowania przez wstawianie.
Wyciągnij odpowiednie wnioski.
2. Ile razy zostanie podzielony zbiór 128 elementowy w trakcie działania algorytmu sortowania przez scalanie?
3. Podany algorytm scalania podzbiorów uporządkowanych można ulepszyć, jeśli rozważymy przypadki wyczerpania elementów w jednym
z podzbiorów. Wtedy elementy drugiego podzbioru można bezpośrednio przekopiować do zbioru tymczasowego bez wykonywania
dalszych porównań. Zaprojektuj taki algorytm, ułóż na jego podstawie program i sprawdź, czy to usprawnienie daje spodziewane
przyspieszenie sortowania zbioru.
4. Określ klasę złożoności obliczeniowej operacji scalania dwóch zbiorów uporządkowanych m- i n elementowych.
5. Jak należy scalać podzbiory w algorytmie sortowania przez scalanie, aby był zachowany warunek stabilności - elementy równe
zachowują swoją kolejność w zbiorze posortowanym.

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany
Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 110 / 209


Algorytmy Sortujące - Sortowanie przez scalanie 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0013.php 111 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Drzewo binarne 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie stogowe
Heap Sort
Podrozdziały Tematy pokrewne
Drzewo binarne Tworzenie kopca
Odwzorowanie drzewa binarnego w tablicy Rozbiór kopca
Zrównoważone drzewa binarne Sortowanie przez kopcowanie
Ścieżki w drzewach binarnych
Podsumowanie nowej terminologii
Zadania dla ambitnych

Drzewo binarne
Binary Tree
Dotychczas operowaliśmy na prostych strukturach danych, takich jak tablice. W tablicy elementy ułożone są zgodnie z ich
numeracją, czyli indeksami. Jeśli za punkt odniesienia weźmiemy element d[i] (i = 2,3,..,n-1; n - liczba elementów w tablicy), to
elementem poprzedzającym go będzie element o mniejszym o 1 indeksie, czyli d[i - 1]. Elementem następnym będzie element o
indeksie o 1 większym, czyli d[i + 1]. Jest to tzw. hierarchia liniowa - elementy następują jeden za drugim. Graficznie możemy
przedstawić to tak:

Pierwszy element d[1] nie posiada poprzednika (ang. predecessor - elementu poprzedzającego w ciągu). Ostatni element d[n]
nie posiada następnika (ang. successor - elementu następnego w ciągu). Wszystkie pozostałe elementy posiadają poprzedniki i
następniki.
Drzewo binarne jest hierarchiczną strukturą danych, którego elementy będziemy nazywali węzłami (ang. node) lub
wierzchołkami. W hierarchii liniowej każdy element może posiadać co najwyżej jeden następnik. W drzewie binarnym każdy
węzeł może posiadać dwa następniki (stąd pochodzi nazwa drzewa - binarny = dwójkowy, zawierający dwa elementy), które
nazwiemy potomkami. dziećmi lub węzłami potomnymi danego węzła (ang. child node).
Węzły są połączone krawędziami symbolizującymi następstwo kolejnych elementów w strukturze drzewa
binarnego. Według rysunku po prawej stronie węzeł A posiada dwa węzły potomne: B i C. Węzeł B nosi nazwę
lewego potomka (ang. left child node), a węzeł C nosi nazwę prawego potomka (ang. right child node).
Z kolei węzeł B posiada węzły potomne D i E, a węzeł C ma węzły potomne F i G. Jeśli dany węzeł nie
posiada dalszych węzłów potomnych, to jest w strukturze drzewa binarnego węzłem terminalnym. Taki
węzeł nosi nazwę liścia (ang. leaf node). Na naszym rysunku liściami są węzły terminalne D, E, F i G.
Rodzicem, przodkiem (ang. parent node) lub węzłem nadrzędnym będziemy nazywać węzeł leżący na
wyższym poziomie hierarchii drzewa binarnego. Dla węzłów B I C węzłem nadrzędnym jest węzeł A. Podobnie
dla węzłów D i E węzłem nadrzędnym będzie węzeł B, a dla F i G będzie to węzeł C.
Węzeł nie posiadający rodzica nazywamy korzeniem drzewa binarnego (ang. root node). W naszym przykładzie korzeniem jest
węzeł A. Każde drzewo binarne, które zawiera węzły posiada dokładnie jeden korzeń.

Odwzorowanie drzewa binarnego


Jeśli chcemy przetwarzać za pomocą komputera struktury drzew binarnych, to musimy zastanowić się nad sposobem
reprezentacji takich struktur w pamięci. Najprostszym rozwiązaniem jest zastosowanie zwykłej tablicy n elementowej. Każdy
element tej tablicy będzie reprezentował jeden węzeł drzewa binarnego. Pozostaje nam jedynie określenie związku pomiędzy
indeksami elementów w tablicy a położeniem tych elementów w strukturze drzewa binarnego.
Zastosujmy następujące odwzorowanie:

Element d[1] będzie zawsze korzeniem drzewa.


i-ty poziom drzewa binarnego wymaga 2i-1 węzłów. Będziemy je kolejno pobierać z tablicy.
Otrzymamy w ten sposób następujące odwzorowanie elementów tablicy w drzewo binarne:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0014.php 112 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Drzewo binarne 2014-10-03

Dla węzła k-tego wyprowadzamy następujące wzory:

węzły potomne mają indeksy równe:


2k - lewy potomek
2k+1 - prawy potomek
węzeł nadrzędny ma indeks równy [k / 2] (dzielenie całkowitoliczbowe)

Sprawdź, iż podane wzory są również spełnione w drzewach binarnych o większych rozmiarach niż prezentuje nasz przykład
(pomocna może być kartka papieru).

Przykład:
Skonstruować drzewo binarne z elementów zbioru {7 5 9 2 4 6 1}

Operacja Opis

Konstrukcję drzewa binarnego rozpoczynamy od korzenia, który jest pierwszym elementem zbioru, czyli liczbą 7.
7592461

Do korzenia dołączamy dwa węzły potomne, które leżą obok w zbiorze. Są to dwa kolejne elementy, 5 i 9.
7592461

Do lewego węzła potomnego (5) dołączamy jego węzły potomne. Są to kolejne liczby w zbiorze, czyli 2 i 4.

7592461

Pozostaje nam dołączyć do prawego węzła ostatnie dwa elementy zbioru, czyli liczby 6 i 1. Drzewo jest
kompletne.

7592461

Zrównoważone drzewa binarne


Balanced Binary Trees
Umówmy się na potrzeby tego artykułu, iż binarne drzewo jest zrównoważone i uporządkowane, jeśli na wszystkich
poziomach za wyjątkiem ostatniego posiada maksymalną liczbę węzłów, a na poziomie ostatnim węzły są ułożone kolejno od
lewej strony. Innymi słowy, jeśli ostatni węzeł drzewa binarnego posiada numer i-ty, to drzewo zawiera wszystkie węzły od numeru
1 do i.
Warunek ten gwarantuje nam, iż każdy element tablicy będzie reprezentował pewien węzeł w drzewie binarnym - czyli w tej
strukturze nie wystąpią dziury.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0014.php 113 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Drzewo binarne 2014-10-03

Drzewo po lewej stronie nie posiada węzła d[7]. Ale posiada wszystkie węzły od d[1] d o d[6], jest zatem zrównoważone i
uporządkowane. Można je bez problemu przedstawić za pomocą tablicy elementów od d[1] do d[6].
Drzewo po prawej stronie nie posiada węzła d[5]. Takiego drzewa nie przedstawimy poprawnie za pomocą tablicy elementów od
d[1] do d[7], ponieważ nie mamy możliwości zaznaczenia (bez dodatkowych zabiegów), iż element d[5] nie należy do struktury
drzewa. Zatem nie będzie to uporządkowane i zrównoważone drzewo binarne.
W uporządkowanych i zrównoważonych drzewach binarnych bardzo prosto można sprawdzić, czy k-ty węzeł jest liściem. Będzie
tak, jeśli węzeł ten nie posiada węzłów potomnych. Zatem, jeśli drzewo binarne składa się z n węzłów, to wystarczy sprawdzić,
czy 2k > n. Jeśli tak, węzeł jest liściem. Jeśli nie, węzeł posiada potomka o indeksie 2k, zatem nie może być liściem.

Ścieżki na drzewach binarnych


Ścieżką nazwiemy ciąg węzłów drzewa binarnego spełniających warunek, iż każdy węzeł poprzedni jest rodzicem węzła
następnego. Jeśli ścieżka składa się z k węzłów, to długością ścieżki jest liczba k - 1.

Na powyższym rysunku zaznaczona została ścieżka biegnąca poprzez węzły {d[1], d[3], d[6], d[13]}. Ścieżka ta zawiera
cztery węzły, ma zatem długość równą 3.
Wysokością drzewa binarnego nazwiemy długość najdłuższej ścieżki od korzenia do liścia. W powyższym przykładzie najdłuższa
taka ścieżka ma długość 3, zatem zaprezentowane drzewo binarne ma wysokość równą 3.
Dla n węzłów zrównoważone drzewo binarne ma wysokość równą:

h = [log2n]

Podsumowanie nowej terminologii


węzeł (ang. node) - element drzewa binarnego
rodzic, węzeł nadrzędny, przodek (ang, parent node) - węzeł leżący o 1 poziom wyżej w hierarchii
dziecko, potomek, węzeł potomny (ang. child node) - węzeł leżący o 1 poziom niżej w hierarchii, dla którego bieżący węzeł
jest rodzicem.
korzeń drzewa (ang. root node) - pierwszy węzeł na najwyższym poziomie hierarchii, który nie posiada
rodzica
liść, węzeł terminalny (ang. leaf node) - węzeł nie posiadający węzłów potomnych
ścieżka (ang. path) - droga na drzewie binarnym wiodąca poprzez poszczególne
wierzchołki

Zadania dla ambitnych


1. Zaprojektuj algorytm, który wyznacza ścieżkę od korzenia drzewa binarnego do wskazanego węzła. Na podstawie algorytmu napisz
odpowiedni program w wybranym języku programowania.
2. Wykorzystując zaprojektowany w zadaniu 1 algorytm napisz program, który dla zadanego drzewa binarnego wyznacza wszystkie DLA
GENIUSZA
ścieżki od korzenia do poszczególnych liści.
3. Zaprojektuj algorytm, który sprawdza, czy istnieje ścieżka pomiędzy dwoma węzłami drzewa binarnego. Na podstawie tego algorytmu
napisz program w wybranym języku programowania.

Zobacz również na: Tworzenie kopca | Rozbiór kopca | Sortowanie przez kopcowanie

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0014.php 114 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Drzewo binarne 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0014.php 115 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie stogowe
Heap Sort
Podrozdziały Tematy pokrewne
Kopiec Programy Podsumowanie Drzewo binarne
Algorytm tworzenia kopca Program w języku Pascal Zadania dla ambitnych Rozbiór kopca
Specyfikacja problemu Program w języku C++ Sortowanie przez kopcowanie
Lista kroków Program w języku Basic
Schemat blokowy Program w języku JavaScript

Kopiec
Heap
Kopiec jest drzewem binarnym, w którym wszystkie węzły spełniają następujący warunek (zwany warunkiem kopca):

Węzeł nadrzędny jest większy lub równy węzłom potomnym (w porządku malejącym relacja jest odwrotna -
mniejszy lub równy).

Konstrukcja kopca jest nieco bardziej skomplikowana od konstrukcji drzewa binarnego, ponieważ musimy dodatkowo troszczyć
się o zachowanie warunku kopca. Zatem po każdym dołączeniu do kopca nowego węzła, sprawdzamy odpowiednie warunki i
ewentualnie dokonujemy wymian węzłów na ścieżce wiodącej od dodanego węzła do korzenia.

Przykład:
Skonstruować kopiec z elementów zbioru {7 5 9 6 7 8 10}

Operacja Opis

Budowę kopca rozpoczynamy od pierwszego elementu zbioru, który staje się korzeniem.
7 5 9 6 7 8 10

Do korzenia dołączamy następny element. Warunek kopca jest zachowany.


7 5 9 6 7 8 10

Dodajemy kolejny element ze zbioru.


7 5 9 6 7 8 10

Po dodaniu elementu 9 warunek kopca przestaje być spełniony. Musimy go przywrócić.


W tym celu za nowy węzeł nadrzędny wybieramy nowo dodany węzeł. Poprzedni węzeł
nadrzędny wędruje w miejsce węzła dodanego - zamieniamy węzły 7 i 9 miejscami.

Po wymianie węzłów 7 i 9 warunek kopca jest spełniony.

Dołączamy kolejny element 6. Znów warunek kopca przestaje być spełniony -


zamieniamy miejscami węzły 5 i 6.

7 5 9 6 7 8 10

Po wymianie węzłów 5 i 6 warunek kopca jest spełniony.

Dołączamy kolejny element 7. Warunek kopca przestaje obowiązywać. Zamieniamy


miejscami węzły 6 i 7.

7 5 9 6 7 8 10

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 116 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

Po wymianie węzłów 6 i 7 warunek kopca obowiązuje.

Dołączamy kolejny węzeł. Powoduje on naruszenie warunku kopca, zatem wymieniamy


ze sobą węzły 7 i 8.

7 5 9 6 7 8 10

Po wymianie węzłów 7 i 8 warunek kopca znów obowiązuje.

Dołączenie ostatniego elementu znów narusza warunek kopca. Zamieniamy miejscami


węzeł 8 z węzłem 10.

7 5 9 6 7 8 10

Po wymianie węzłów 8 i 10 warunek kopca został przywrócony na tym poziomie.


Jednakże węzeł 10 stał się dzieckiem węzła 9. Na wyższym poziomie drzewa warunek
kopca jest naruszony. Aby go przywrócić znów wymieniamy miejscami węzły, tym
razem węzeł 9 z węzłem 10.

Po wymianie tych węzłów warunek kopca obowiązuje w całym drzewie - zadanie jest
wykonane.

Charakterystyczną cechą kopca jest to, iż korzeń zawsze jest największym (w porządku malejącym najmniejszym) elementem z
całego drzewa binarnego.

Algorytm
Poniżej przedstawiamy algorytm konstrukcji kopca z elementów zbioru.

Specyfikacja problemu
Dane wejściowe
d[ ] - Zbiór zawierający elementy do wstawienia do kopca. Numeracja elementów rozpoczyna się od 1.
n - Ilość elementów w zbiorze, n Î N
Dane wyjściowe
d[ ] - Zbiór zawierający kopiec

Zmienne pomocnicze
i - zmienna licznikowa pętli umieszczającej kolejne elementy zbioru w kopcu, i Î N, i Î {2,3,...,n}
j,k - indeksy elementów leżących na ścieżce od wstawianego elementu do korzenia, j,k Î C
x - zmienna pomocnicza przechowująca tymczasowo element wstawiany do kopca

Lista kroków
K01: Dla i = 2, ..., n: wykonuj K02...K05
K02: j ← i; k ← j div 2
K03: x ← d[i]
K04: Dopóki (k > 0) (d[k] < x): wykonuj
d[j] ← d[k]
j ←k
k ← j div 2
K05: d[j] ← x
K06: Zakończ
Uwaga: przy porządku malejącym należy zmienić drugi warunek w kroku K04 z d[k] < x na d[k] > x.

Schemat blokowy
Algorytm tworzy kopiec w tym samym zbiorze wejściowym d[ ]. Nie wymaga zatem dodatkowych

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 117 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

struktur danych i ma złożoność pamięciową klasy O(n).


Pętla nr 1 wyznacza kolejne elementy wstawiane do kopca. Pierwszy element pomijamy, ponieważ
zostałby i tak na swoim miejscu. Dlatego pętla rozpoczyna wstawianie od elementu nr 2.
Wewnątrz pętli nr 1 inicjujemy kilka zmiennych:

j - pozycja wstawianego elementu (liścia)


k - pozycja elementu nadrzędnego (przodka)
x - zapamiętuje wstawiany element

Następnie rozpoczynamy pętlę warunkową nr 2, której zadaniem jest znalezienie w kopcu miejsca do
wstawienia zapamiętanego elementu w zmiennej x. Pętla ta wykonuje się do momentu osiągnięcia
korzenia kopca (k = 0) lub znalezienia przodka większego od zapamiętanego elementu. Wewnątrz
pętli przesuwamy przodka na miejsce potomka, aby zachować warunek kopca, a następnie
przesuwamy pozycję j na pozycję zajmowaną wcześniej przez przodka. Pozycja k staje się pozycją
nowego przodka i pętla się kontynuuje. Po jej zakończeniu w zmiennej j znajduje się numer pozycji w
zbiorze d[ ], na której należy umieścić element w x.
Po zakończeniu pętli nr 1 w zbiorze zostaje utworzona struktura kopca.

Programy
Programy tworzą kopiec z pseudolosowo wygenerowanych 15 elementów zbioru. Wynik działania jest następnie prezentowany w
formie drzewa binarnego.

Efekt uruchomienia programu


Tworzenie kopca
----------------------
(C)2005 Jerzy Walaszek
9
9 9
7 8 8 9
7 3 4 6 8 5 8 6
0 5 0 1 1 4 2 4 2 5 2 0 4 6 4 5

DevPascal
// Konstruowanie kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program kopiec;
const N = 31; // liczba elementów
var
d : array[1..N] of integer;
i,j,k,x : integer;
begin
randomize;
writeln(' Tworzenie kopca');
writeln('----------------------');
writeln('(C)2005 Jerzy Walaszek');
writeln;
// Inicjujemy zbiór d[] liczbami pseudolosowymi od 0 do 9
for i := 1 to N do d[i] := random(10);
// Budujemy kopiec
for i := 2 to N do
begin
j := i; k := j div 2;
x := d[i];
while (k > 0) and (d[k] < x) do
begin
d[j] := d[k];
j := k; k := j div 2;
end;
d[j] := x;
end;
// Prezentujemy wyniki
x := (N + 1) div 2; k := 2;
for i := 1 to N do
begin
for j := 1 to x - 1 do write(' ');
write(d[i]);
for j := 1 to x do write(' ');

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 118 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

if i + 1 = k then
begin
k := k + k; x := x div 2; writeln;
end;
end;
// Gotowe
writeln; writeln;
write('KONIEC, nacisnij klawisz Enter...');
readln;
end.

Code::Blocks
// Konstruowanie kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int N = 31; // liczba elementów
int d[N + 1],i,j,k,x;
srand((unsigned)time(NULL));
cout << " Tworzenie kopca\n"
"----------------------\n"
"(C)2005 Jerzy Walaszek\n\n";
// Inicjujemy zbiór d[] liczbami pseudolosowymi od 0 do 9
for(i = 1; i <= N; i++) d[i] = rand() % 10;
// Budujemy kopiec
for(i = 2; i <= N; i++)
{
j = i; k = j / 2;
x = d[i];
while((k > 0) && (d[k] < x))
{
d[j] = d[k];
j = k; k = j / 2;
}
d[j] = x;
}
// Prezentujemy wyniki
x = (N + 1) / 2; k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j <= x - 1; j++) cout << " ";
cout << d[i];
for(j = 1; j <= x; j++) cout << " ";
if(i + 1 == k)
{
k += k; x /= 2; cout << endl;
}
}
// Gotowe
cout << endl << endl;
return 0;
}

Free Basic
' Konstruowanie kopca
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Const N = 31 ' liczba elementów
Dim d(N) As Integer
Dim i As Integer, j As Integer, k As Integer, x As Integer
Randomize
Print " Tworzenie kopca"
Print "----------------------"

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 119 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

Print "(C)2005 Jerzy Walaszek"


Print
' Inicjujemy zbiór d[] liczbami pseudolosowymi od 0 do 9
For i = 1 To N: d(i) = Int(Rnd * 10): Next
' Budujemy kopiec
For i = 2 To N
j = i: k = j \ 2
x = d(i)
While (k > 0) And (d(k) < x)
d(j) = d(k)
j = k: k = j / 2
Wend
d(j) = x
Next
' Prezentujemy wyniki
x = (N + 1) \ 2: k = 2
For i = 1 To N
For j = 1 To x - 1: Print " ";: Next
Print Using "#";d(i);
For j = 1 To x: Print " ";: Next
If i + 1 = k Then
k = k + k: x = x \ 2:
Print
End If
Next
' Gotowe
Print: Print
Print "KONIEC, nacisnij klawisz Enter..."
Sleep
End

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="frmheap">
<h3 style="text-align: center">Tworzenie kopca</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Buduj Kopiec" name="B1">
</p>
<p style="TEXT-ALIGN: center">
<font face="Courier New"><span id="t_out">.</span></font>
</p>
</form>
<script language=javascript>
// Konstruowanie kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------

function main()
{
var N = 31; // liczba elementów
var d = new Array(N+1);
var i,j,k,x,t;
// Inicjujemy zbiór d[] liczbami pseudolosowymi od 0 do 9
for(i = 1; i <= N; i++) d[i] = Math.floor(Math.random() * 10);
// Budujemy kopiec
for(i = 2; i <= N; i++)
{
j = i; k = Math.floor(j / 2);
x = d[i];
while((k > 0) && (d[k] < x))
{
d[j] = d[k];
j = k; k = Math.floor(j / 2);
}
d[j] = x;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 120 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

}
// Prezentujemy wyniki
t = ""; x = (N + 1) / 2; k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j <= x - 1; j++) t += "&nbsp;";
t += d[i];
for(j = 1; j <= x; j++) t += "&nbsp;";
if(i + 1 == k)
{
k += k; x = Math.floor(x / 2); t += "<BR>";
}
}
// Gotowe
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Tworzenie kopca
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Buduj Kopiec
.

Podsumowanie
W rozdziale opisaliśmy bardzo prosty algorytm pozwalający konstruować kopiec. Algorytm ten posiada pesymistyczną klasę
złożoności czasowej O(n log n) (liniowo logarytmiczną) - każde wstawienie nowego elementu na stos może wymagać tyle
przesunięć, ile jest węzłów kopca na ścieżce od miejsca wstawiania do korzenia drzewa. Nie trudno zauważyć, iż liczba ta jest
równa lub mniejsza od wysokości kopca, czyli log2n. Ponieważ operację tę wykonujemy (n - 1) razy, to dostajemy górne
oszacowanie właśnie O(n log n).
W przypadku optymistycznym, gdy dodanie nowego elementu nie narusza warunku kopca, algorytm ma klasę czasowej
złożoności obliczeniowej O(n) (liniową). Jednakże cecha ta nie bardzo się nam przyda przy sortowaniu, ponieważ zbiór ze
strukturą kopca nie tworzy zbioru uporządkowanego liniowo - bardzo łatwo się możesz o tym przekonać analizując podany na
początku rozdziału przykład.

Zadania dla ambitnych


1. Na podstawie naszego algorytmu wyznacz maksymalną liczbę operacji porównań przy tworzeniu kopca z 31 elementów.
2. Nasz algorytm nie jest najefektywniejszym algorytmem do konstrukcji kopców. Poszukaj w sieci Internet informacji o algorytmie Floyda.
3. Zaprojektuj algorytm, który przyjmie jako parametry wejściowe liczbę elementów oraz zbiór ze strukturą kopca i sprawdzi, czy faktycznie
jest w niej zachowany warunek kopca dla wszystkich węzłów. Jeśli tak, to algorytm powinien zwracać wartość logiczną true, a false w
przypadku przeciwnym.

Zobacz również na: | Drzewo binarne | Rozbiór kopca | Sortowanie przez kopcowanie

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 121 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Tworzenie kopca 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0015.php 122 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie stogowe
Heap Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Drzewo binarne
Specyfikacja problemu Program w języku Pascal Tworzenie kopca
Lista kroków Program w języku C++ Sortowanie przez kopcowanie
Schemat blokowy Program w języku Basic
Program w języku JavaScript

Algorytm
W tym rozdziale nauczymy się rozbierać kopiec. Zasada jest następująca:
1. Zamień miejscami korzeń z ostatnim liściem, który wyłącz ze struktury kopca. Elementem pobieranym z kopca jest
zawsze jego korzeń, czyli element największy.
2. Jeśli jest to konieczne, przywróć warunek kopca idąc od korzenia w dół.
3. Kontynuuj od kroku 1, aż kopiec będzie pusty.

Przykład:
Dokonaj rozbioru następującego kopca:

Operacja Opis

Rozbiór kopca rozpoczynamy od korzenia, który usuwamy ze struktury kopca. W


miejsce korzenia wstawiamy ostatni liść.

9
Poprzednia operacja zaburzyła strukturę
kopca. Idziemy zatem od korzenia w dół
struktury przywracając warunek kopca -
przodek większy lub równy od swoich
potomków. Praktycznie polega to na
zamianie przodka z największym
potomkiem. Operację kontynuujemy
dotąd, aż natrafimy na węzły spełniające
warunek kopca.

Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem

89

W nowym kopcu przywracamy warunek


kopca.

Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem

789

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 123 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

W nowym kopcu przywracamy warunek kopca. W tym


przypadku już po pierwszej wymianie węzłów warunek koca jest
zachowany w całej strukturze.

Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem

5789

Przywracamy warunek kopca w strukturze.

Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem

45789

Przywracamy warunek kopca w strukturze.

Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem.

245789

Po wykonaniu poprzedniej operacji usunięcia w kopcu pozostał tylko jeden element -


usuwamy go. Zwróć uwagę, iż usunięte z kopca elementy tworzą ciąg uporządkowany.
1245789

Operację rozbioru kopca można przeprowadzić w miejscu. Jeśli mamy zbiór d[ ] ze strukturą kopca, to idąc od końca zbioru
(ostatnie liście drzewa) w kierunku początku zamieniamy elementy z pierwszym elementem zbioru (korzeń drzewa), a następnie
poruszając się od korzenia w dół przywracamy warunek kopca w kolejno napotykanych węzłach.

Specyfikacja problemu
Dane wejściowe
d[ ] - Zbiór zawierający poprawną strukturę kopca. Elementy są numerowane począwszy od 1.
n - Ilość elementów w zbiorze, n Î N
Dane wyjściowe
d[ ] - Zbiór zawierający elementy pobrane z kopca ułożone w porządku rosnącym

Zmienne pomocnicze
i - zmienna licznikowa pętli pobierającej kolejne elementy z kopca, i Î N, i Î {n,n-1,...,2}
j,k - indeksy elementów leżących na ścieżce w dół od korzenia, j,k Î N
m - indeks większego z dwóch elementów potomnych, m Î N

Lista kroków
K01: Dla i = n, n - 1, ..., 2: wykonuj K02...K08
K02: d[1] ↔ d[i]
K03: j ← 1; k ← 2
K04: Dopóki (k < i) wykonuj K05...K08
K05: Jeżeli (k + 1 < i) (d[k + 1] > d[k]), to m ← k + 1
inaczej m ← k
K06: Jeżeli d[m] ≤ d[j], to wyjdź z pętli K04 i kontynuuj następny obieg K01
K07: d[j] ↔ d[m]
K08: j ← m; k ← j + j
K09: Zakończ

Schemat blokowy
Rozbiór kopca wykonywany jest w dwóch zagnieżdżonych pętlach. Pętla nr 1 zamienia
miejscami kolejne liście ze spodu drzewa z korzeniem. Zadaniem pętli nr 2 jest przywrócenie w
strukturze warunku kopca.
Pętla nr 1 przebiega wstecz indeksy elementów zbioru d[ ] poczynając od indeksu n a
kończąc na indeksie 2. Element i-ty jest wymieniany z korzeniem kopca. Po tej wymianie

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 124 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

rozpoczynamy w pętli nr 2 przeglądanie drzewa od korzenia w dół. Zmienna j przechowuje


indeks przodka, zmienna k przechowuje indeks lewego potomka. Pętla nr 2 kończy się, gdy
węzeł j-ty nie posiada potomków. Wewnątrz pętli wyznaczamy w zmiennej m indeks
większego z dwóch węzłów potomnych. Następnie sprawdzamy, czy w węźle nadrzędnym j-
tym jest zachowany warunek kopca. Jeśli tak, to następuje wyjście z pętli nr 2. W przeciwnym
razie zamieniamy miejscami węzeł nadrzędny j-ty z jego największym potomkiem m-tym i za
nowy węzeł nadrzędny przyjmujemy węzeł m-ty. W zmiennej k wyznaczamy indeks jego
lewego potomka i kontynuujemy pętlę nr 2.
Po wyjściu z pętli nr 2 zmniejszamy zmienną i o 1 - przenosimy się do kolejnego, ostatniego
liścia drzewa i kontynuujemy pętlę nr 1.
W celu wyznaczenia klasy złożoności obliczeniowej algorytmu rozbioru kopca zauważamy, iż
pętla zewnętrzna nr 1 wykona się n - 1 razy, a w każdym obiegu tej pętli pętla wewnętrzna
wykona się maksymalnie log2n razy. Daje to zatem górne oszacowanie O(n log n) w
przypadku pesymistycznym oraz O(n) w przypadku optymistycznym, który wystąpi tylko
wtedy, gdy zbiór d[ ] będzie zbudowany z ciągu tych samych elementów.

Programy
Efekt uruchomienia programu
Rozbior kopca
----------------------
(C)2005 Jerzy Walaszek
Zbior wejsciowy ze struktura kopca:
9 7 8 0 6 2 6 0 0 0 4 0 0 6 4
9
7 8
0 6 2 6
0 0 0 4 0 0 6 4
Zbior wyjsciowy po rozbiorze kopca:
0 0 0 0 0 0 2 4 4 6 6 6 7 8 9

DevPascal
// Rozbiór kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program kopiec;
const N = 15; // liczba elementów
var
d : array[1..N] of integer;
i,j,k,m,x : integer;
begin
randomize;
writeln(' Rozbior kopca');
writeln('----------------------');
writeln('(C)2005 Jerzy Walaszek');
writeln;
// W zbiorze d konstruujemy kopiec
d[1] := 9;
for i := 2 to N do d[i] := random(d[i div 2] + 1);
// Prezentujemy kopiec
writeln('Zbior wejsciowy ze struktura kopca:');
writeln;
for i := 1 to N do write(d[i]:2);
writeln; writeln;
x := (N + 1) div 2; k := 2;
for i := 1 to N do
begin
for j := 1 to x - 1 do write(' ');
write(d[i]);
for j := 1 to x do write(' ');
if i + 1 = k then
begin
k := k + k; x := x div 2; writeln;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 125 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

end;
end;
// Rozbieramy kopiec
for i := N downto 2 do
begin
x := d[1]; d[1] := d[i]; d[i] := x;
j := 1; k := 2;
while k < i do
begin
if (k + 1 < i) and (d[k + 1] > d[k]) then
m := k + 1
else
m := k;
if d[m] <= d[j] then break;
x := d[j]; d[j] := d[m]; d[m] := x;
j := m; k := j + j;
end;
end;
// Wyświetlamy wynik rozbioru kopca
writeln;
writeln('Zbior wyjsciowy po rozbiorze kopca:');
writeln;
for i := 1 to N do write(d[i]:2);
// Gotowe
writeln; writeln;
write('KONIEC, nacisnij klawisz Enter...'); readln;
end.

Code::Blocks
// Rozbiór kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int N = 15; // liczba elementów
int d[N + 1],i,j,k,m,x;
srand((unsigned)time(NULL));
cout << " Rozbior kopca\n"
"----------------------\n"
"(C)2005 Jerzy Walaszek\n\n"
"Zbior wejsciowy ze struktura kopca:\n\n";
// W zbiorze d konstruujemy kopiec
d[1] = 9;
for(i = 2; i <= N; i++) d[i] = rand() % (d[i / 2] + 1);
// Prezentujemy kopiec
for(i = 1; i <= N; i++) cout << setw(2) << d[i];
cout << endl << endl;
x = (N + 1) / 2; k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j < x; j++) cout << " ";
cout << d[i];
for(j = 1; j <= x; j++) cout << " ";
if(i + 1 == k)
{
k += k; x /= 2; cout << endl;
}
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
swap(d[1], d[i]);
j = 1; k = 2;
while(k < i)
{
if((k + 1 < i) && (d[k + 1] > d[k]))
m = k + 1;
else
m = k;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 126 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

if(d[m] <= d[j]) break;


swap(d[j], d[m]);
j = m; k = j + j;
}
}
// Wyświetlamy wynik rozbioru kopca
cout << endl << "Zbior wyjsciowy po rozbiorze kopca:\n\n";
for(i = 1; i <= N; i++) cout << setw(2) << d[i];
cout << endl << endl;
// Gotowe
return 0;
}

Free Basic
' Rozbiór kopca
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Const N = 15 ' liczba elementów
Dim d(N) As Integer, i As Integer, j As Integer
Dim k As Integer, m As Integer, x As Integer
Randomize
Print " Rozbior kopca"
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' W zbiorze d konstruujemy kopiec
d(1) = 9
For i = 2 To N: d(i) = Int(Rnd * (d(i \ 2) + 1)): Next
' Prezentujemy kopiec
Print "Zbior wejsciowy ze struktura kopca:"
Print
For i = 1 To N: Print Using "##";d(i);:Next
Print: Print
x = (N + 1) \ 2: k = 2
For i = 1 To N
For j = 1 To x - 1: Print " ";: Next
Print Using "#";d(i);
For j = 1 To x: Print " ";: Next
If i + 1 = k Then
k = k + k: x = x \ 2: Print
End If
Next
' Rozbieramy kopiec
For i = N To 2 Step -1
Swap d(1), d(i)
j = 1: k = 2
While k < i
If (k + 1 < i) And (d(k + 1) > d(k)) Then
m = k + 1
Else
m = k
End If
If d(m) <= d(j) Then Exit While
Swap d(j), d(m)
j = m: k = j + j
Wend
Next
' Wyświetlamy wynik rozbioru kopca
Print
Print "Zbior wyjsciowy po rozbiorze kopca:"
Print
For i = 1 To N: Print Using "##";d(i);:Next
Print: Print
' Gotowe
Print "KONIEC, nacisnij klawisz Enter..."
Sleep
End

JavaScript
<html>
<head>
</head>
<body>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 127 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03
<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="frmheap">
<h3 style="text-align: center">Rozbiór kopca</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Rozbierz Kopiec" name="B1">
</p>
<p style="TEXT-ALIGN: center">
<font face="Courier New"><span id="t_out">.</span></font>
</p>
</form>
<script language=javascript>
// Rozbiór kopca
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------

function main()
{
var N = 15; // liczba elementów
var d = new Array(N + 1);
var i,j,k,x,t;
// W zbiorze d konstruujemy kopiec
d[1] = 9;
for(i = 2; i <= N; i++)
d[i] = Math.floor(Math.random() * (d[Math.floor(i / 2)] + 1));
// Prezentujemy kopiec
t = "";
for(i = 1; i <= N; i++) t += d[i] + " ";
t += "<BR><BR>";
x = Math.floor((N + 1) / 2); k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j < x; j++) t += "&nbsp;";
t += d[i];
for(j = 1; j <= x; j++) t += "&nbsp;";
if(i + 1 == k)
{
k += k; x = Math.floor(x / 2); t += "<BR>";
}
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
x = d[1]; d[1] = d[i]; d[i] = x;
j = 1; k = 2;
while(k < i)
{
if((k + 1 < i) && (d[k + 1] > d[k]))
m = k + 1;
else
m = k;
if(d[m] <= d[j]) break;
x = d[j]; d[j] = d[m]; d[m] = x;
j = m; k = j + j;
}
}
// Wyświetlamy wynik rozbioru kopca
t += "<BR>";
for(i = 1; i <= N; i++) t += d[i] + " ";
// Gotowe
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 128 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie - Rozbiór kopca 2014-10-03

Rozbiór kopca
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Rozbierz Kopiec
.

Zobacz również na: Drzewo binarne | Tworzenie kopca | Sortowanie przez kopcowanie

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0016.php 129 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie stogowe
Heap Sort
Podrozdziały Tematy pokrewne
Algorytm rozbioru kopca Programy Badanie algorytmów sortujących Drzewo binarne
Specyfikacja problemu Program w języku Pascal Podsumowanie Tworzenie kopca
Lista kroków Program w języku C++ Zadania dla ambitnych Rozbiór kopca
Program w języku Basic
Program w języku JavaScript

Algorytm
Jeśli przeczytałeś uważnie poprzednie dwa rozdziały, to zasadę sortowania przez kopcowanie zrozumiesz od razu - w zbiorze
tworzymy kopiec, a następnie dokonujemy jego rozbioru. W wyniku wykonania tych dwóch operacji zbiór zostanie posortowany.

Specyfikacja problemu
Dane wejściowe
d[ ] - Zbiór zawierający elementy do posortowania, które są numerowane począwszy od 1.
n - Ilość elementów w zbiorze, n Î N
Dane wyjściowe
d[ ] - Zbiór zawierający elementy posortowane rosnąco

Zmienne pomocnicze i funkcje


Twórz_kopiec - procedura budująca kopiec z elementów zbioru d[ ]. Kopiec powstaje w zbiorze d[ ].
Rozbierz_kopiec - procedura dokonująca rozbioru kopca utworzonego w zbiorze d[ ]. Wynik rozbioru trafia z
powrotem do zbioru d[ ].

Lista kroków
K01: Twórz_kopiec
K02: Rozbierz_kopiec
K03: Zakończ algorytm
Ponieważ sortowanie przez kopcowanie składa się z dwóch następujących bezpośrednio po sobie operacji o klasie czasowej
złożoności obliczeniowej O(n log n), to dla całego algorytmu klasa złożoności również będzie wynosić O(n log n).

Programy
Efekt uruchomienia programu
Sortowanie przez kopcowanie
-----------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
48 40 48 29 21 11 12 63 77 89 99 97 80 62 64 32 28 5 16 36
Po sortowaniu:
5 11 12 16 21 28 29 32 36 40 48 48 62 63 64 77 80 89 97 99

DevPascal
// Sortowanie przez kopcowanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program heap_sort;
const N = 20; // liczebność zbioru

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 130 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

var
d : array[1..N] of integer;
i,j,k,m,x : integer;
begin
writeln(' Sortowanie przez kopcowanie ');
writeln('-----------------------------');
writeln(' (C)2005 Jerzy Walaszek');
writeln;
writeln('Przed sortowaniem:'); writeln;
// Wypełniamy tablicę liczbami pseudolosowymi i wyświetlamy je
randomize;
for i := 1 to N do
begin
d[i] := random(100); write(d[i] : 4);
end;
// Budujemy kopiec
for i := 2 to N do
begin
j := i; k := j div 2;
x := d[i];
while (k > 0) and (d[k] < x) do
begin
d[j] := d[k];
j := k; k := j div 2;
end;
d[j] := x;
end;
// Rozbieramy kopiec
for i := N downto 2 do
begin
x := d[1]; d[1] := d[i]; d[i] := x;
j := 1; k := 2;
while k < i do
begin
if (k + 1 < i) and (d[k + 1] > d[k]) then
m := k + 1
else
m := k;
if d[m] <= d[j] then break;
x := d[j]; d[j] := d[m]; d[m] := x;
j := m; k := j + j;
end;
end;
// Wyświetlamy wynik sortowania
writeln('Po sortowaniu:'); writeln;
for i := 1 to N do write(d[i] : 4);
writeln;
writeln('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie przez kopcowanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int N = 20; // liczebność zbioru
int d[N + 1],i,j,k,m,x;
srand((unsigned)time(NULL));
cout << " Sortowanie przez kopcowanie \n"
"-----------------------------\n"
" (C)2005 Jerzy Walaszek\n\n"
"Przed sortowaniem:\n\n";
// Wypełniamy tablicę liczbami pseudolosowymi i wyświetlamy je
for(i = 1; i <= N; i++)
{
d[i] = rand() % 100; cout << setw(4) << d[i];
}
cout << endl;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 131 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

// Budujemy kopiec
for(i = 2; i <= N; i++)
{
j = i; k = j / 2;
x = d[i];
while((k > 0) && (d[k] < x))
{
d[j] = d[k];
j = k; k = j / 2;
}
d[j] = x;
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
swap(d[1], d[i]);
j = 1; k = 2;
while(k < i)
{
if((k + 1 < i) && (d[k + 1] > d[k]))
m = k + 1;
else
m = k;
if(d[m] <= d[j]) break;
swap(d[j], d[m]);
j = m; k = j + j;
}
}
// Wyświetlamy wynik sortowania
cout << "Po sortowaniu:\n\n";
for(i = 1; i <= N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie przez kopcowanie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Const N = 20 ' liczebność zbioru
Dim d(N) As Integer, i As Integer, j As Integer
Dim k As Integer, m As Integer, x As Integer
Print " Sortowanie przez kopcowanie"
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
' Budujemy kopiec
For i = 2 To N
j = i: k = j \ 2
x = d(i)
While (k > 0) And (d(k) < x)
d(j) = d(k)
j = k: k = j / 2
Wend
d(j) = x
Next
' Rozbieramy kopiec
For i = N To 2 Step -1
Swap d(1), d(i)
j = 1: k = 2
While k < i
If (k + 1 < i) And (d(k + 1) > d(k)) Then
m = k + 1
Else
m = k
End If
If d(m) <= d(j) Then Exit While
Swap d(j), d(m)
j = m: k = j + j
Wend
Next

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 132 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

' Wyświetlamy wynik sortowania


Print "Po sortowaniu:": Print
For i = 1 To N: Print Using "####";d(i);: Next
Print
Print "Nacisnij Enter..."
Sleep
End

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="frmheapsort">
<h3 style="text-align: center">Sortowanie Przez Kopcowanie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Przez Kopcowanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
function main()
{
var N = 20; // liczba elementów
var d = new Array(N + 1);
var i,j,k,x,t;
// Najpierw wypełniamy tablicę d[] liczbami pseudolosowymi
for(i = 1; i <= N; i++) d[i] = Math.floor(Math.random() * 100);
t = "Przed sortowaniem:<BR><BR>";
for(i = 1; i <= N; i++) t += d[i] + " ";
t += "<BR><BR>";
// Budujemy kopiec
for(i = 2; i <= N; i++)
{
j = i; k = Math.floor(j / 2);
x = d[i];
while((k > 0) && (d[k] < x))
{
d[j] = d[k];
j = k; k = Math.floor(j / 2);
}
d[j] = x;
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
x = d[1]; d[1] = d[i]; d[i] = x;
j = 1; k = 2;
while(k < i)
{
if((k + 1 < i) && (d[k + 1] > d[k]))
m = k + 1;
else
m = k;
if(d[m] <= d[j]) break;
x = d[j]; d[j] = d[m]; d[m] = x;
j = m; k = j + j;
}
}
// Wyświetlamy wynik sortowania
t += "Po sortowaniu:<BR><BR>";
for(i = 1; i <= N; i++) t += d[i] + " ";
document.getElementById("t_out").innerHTML = t;
}
</script>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 133 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Przez Kopcowanie


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badania algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania przez kopcowanie w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie przez kopcowanie';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
procedure HeapSort;
var
i,j,k,m : integer;
x : real;
begin
// Budujemy kopiec
for i := 2 to n do
begin
j := i; k := j div 2;
x := d[i];
while (k > 0) and (d[k] < x) do
begin
d[j] := d[k];
j := k; k := j div 2;
end;
d[j] := x;
end;
// Rozbieramy kopiec
for i := n downto 2 do
begin
x := d[1]; d[1] := d[i]; d[i] := x;
j := 1; k := 2;
while k < i do
begin
if (k + 1 < i) and (d[k + 1] > d[k]) then
m := k + 1
else
m := k;
if d[m] <= d[j] then break;
x := d[j]; d[j] := d[m]; d[m] := x;
j := m; k := j + j;
end;
end;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 134 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

function Sort : extended;


begin
QueryPerformanceCounter(addr(qpc1));
HeapSort;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 135 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

else writeln('Na tym komputerze program testowy nie pracuje !');


writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie przez kopcowanie


-----------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000567 0.000541 0.000564 0.000760 0.000500
2000 0.001245 0.001056 0.001251 0.001294 0.001376
4000 0.002780 0.002234 0.003499 0.002826 0.002729
8000 0.006278 0.004912 0.006704 0.006385 0.005474
16000 0.013232 0.011120 0.013231 0.013665 0.012407
32000 0.028305 0.024424 0.028688 0.028988 0.028558
64000 0.060927 0.052423 0.061291 0.062938 0.067073
128000 0.133429 0.112287 0.131137 0.133940 0.158330
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów

(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)


(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania przez kopcowanie
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Przez Kopcowanie


klasa złożoności obliczeniowej optymistyczna
klasa złożoności obliczeniowej typowa O(n log n)
klasa złożoności obliczeniowej pesymistyczna
Sortowanie w miejscu TAK
Stabilność NIE

Klasy złożoności obliczeniowej szacujemy następująco:


optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n log n) O(n log n) O(n log n) O(n log n) O(n log n)
Sortowanie przez kopcowanie
tpo ≈ 7tod tpp ≈ tpk tnp ≈ 4tod
6 3
1. Wszystkie badane czasy są proporcjonalne do nlog2n, zatem wnioskujemy, iż algorytm sortowania przez kopcowanie
posiada klasę czasowej złożoności obliczeniowej równą O(n log n).
2. Najdłużej trwa sortowanie zbioru nieposortowanego. Otrzymane czasy nie różnią się wiele od siebie, co sugeruje, iż
algorytm jest mało czuły na postać danych wejściowych.
3. Ciekawostką jest to, iż czas sortowania zbiorów posortowanych jest dłuższy od sortowania zbioru posortowanego odwrotnie
(jest to najkrótszy czas z otrzymanych, zatem możemy przyjąć, iż dla algorytmu sortowania przez kopcowanie
przypadkiem optymistycznym jest właśnie sortowanie zbioru posortowanego odwrotnie).

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
1 1 1 1 2
Sortowanie przez scalanie ≈ ≈ ≈ ≈ ≈
2 2 2 2 5

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 136 / 209


Algorytmy Sortujące - Sortowanie przez kopcowanie 2014-10-03

2 2 2 2 5
Sortowanie przez kopcowanie
źle źle źle źle źle

4. Z porównania czasów sortowania wynika jasno, iż przedstawiony tutaj algorytm sortowania przez kopcowanie jest około dwa
razy wolniejszy od wcześniej podanego algorytmu sortowania przez scalanie. Zaletą jest sortowanie w miejscu - poprzedni
algorytm wymaga dodatkowej pamięci, co może go dyskwalifikować przy sortowaniu dużych zbiorów danych. Do dalszych
porównań czasów sortowania będziemy dalej stosowali algorytm sortowania przez scalanie.

Zadania dla ambitnych


1. Co należy zmienić w podanym algorytmie, aby uzyskać sortowanie malejące?
2. Udowodnij, iż algorytm sortowania przez kopcowanie nie jest stabilny.
3. Uzasadnij, iż czas sortowania zbioru posortowanego odwrotnie jest najkrótszy.
4. Uzasadnij, iż klasa złożoności algorytmu sortowania przez kopcowanie wynosi O(n log n).

Zobacz również na: Drzewo binarne | Tworzenie kopca | Rozbiór kopca

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0017.php 137 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie szybkie
Quick Sort
Podrozdziały
Algorytm Programy Badanie algorytmów sortujących
Tworzenie partycji Program w języku Pascal Podsumowanie
Specyfikacja problemu Program w języku C++ Zadania dla ambitnych
Lista kroków Program w języku Basic
Schemat blokowy Program w języku JavaScript

Algorytm
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:
1. DZIEL - problem główny zostaje podzielony na podproblemy
2. ZWYCIĘŻAJ - znajdujemy rozwiązanie podproblemów
3. POŁĄCZ - rozwiązania podproblemów zostają połączone w rozwiązanie problemu głównego

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.

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 O(n log n) - stąd pochodzi jego popularność w zastosowaniach. Musimy
jednak pamiętać, iż w pewnych sytuacjach (zależnych od sposobu wyboru piwotu oraz niekorzystnego
ułożenia danych wejściowych) klasa złożoności obliczeniowej tego algorytmu może się degradować do
O(n2), co więcej, poziom wywołań rekurencyjnych może spowodować przepełnienie stosu i zablokowanie
komputera. Z tych powodów algorytmu sortowania szybkiego nie można stosować bezmyślnie w każdej
sytuacji tylko dlatego, iż jest uważany za jeden z najszybszych algorytmów sortujących - zawsze należy
przeprowadzić analizę możliwych danych wejściowych właśnie pod kątem przypadku niekorzystnego -
prof. Tony Hoare czasem lepszym rozwiązaniem może być zastosowanie wcześniej opisanego algorytmu sortowania przez
kopcowanie, który nigdy nie degraduje się do klasy O(n2).

Tworzenie partycji
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 - element podziałowy


piwot ← d[(lewy + prawy) div 2] d[ ] - dzielony zbiór
lewy - indeks pierwszego elementu
prawy - indeks ostatniego elementu

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.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 138 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

Przykład:
Dla przykładu podzielimy na partycje zbiór:
{72473146583926763}

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

Na początku zbioru ustawiamy dwa wskaźniki. Wskaźnik i


7 2 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 będzie przeglądał zbiór do przedostatniej pozycji.
3. i
j Wskaźnik j zapamiętuje miejsce wstawiania elementów
mniejszych od piwotu

7 2 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5
4. i Wskaźnikiem i szukamy elementu mniejszego od piwotu
j

2 7 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5 Znaleziony element wymieniamy z elementem na pozycji


5. i
j j-tej. Po wymianie wskaźnik j przesuwamy o 1 pozycję.

2 7 4 7 3 1 4 6 3 8 3 9 2 6 7 6 5
6. i Szukamy
j

2 4 7 7 3 1 4 6 3 8 3 9 2 6 7 6 5
7. i Wymieniamy i przesuwamy j.
j

2 4 7 7 3 1 4 6 3 8 3 9 2 6 7 6 5
8. i Szukamy
j

2 4 3 7 7 1 4 6 3 8 3 9 2 6 7 6 5
9. i Wymieniamy i przesuwamy j.
j

2 4 3 7 7 1 4 6 3 8 3 9 2 6 7 6 5
10. i Szukamy
j

2 4 3 1 7 7 4 6 3 8 3 9 2 6 7 6 5
11. i Wymieniamy i przesuwamy j.
j

2 4 3 1 7 7 4 6 3 8 3 9 2 6 7 6 5
12. i Szukamy
j

2 4 3 1 4 7 7 6 3 8 3 9 2 6 7 6 5
13. i Wymieniamy i przesuwamy j.
j

2 4 3 1 4 7 7 6 3 8 3 9 2 6 7 6 5
14. i Szukamy
j

2 4 3 1 4 3 7 6 7 8 3 9 2 6 7 6 5
15. i Wymieniamy i przesuwamy j.
j

2 4 3 1 4 3 7 6 7 8 3 9 2 6 7 6 5
16. i Szukamy
j

2 4 3 1 4 3 3 6 7 8 7 9 2 6 7 6 5
17. i Wymieniamy i przesuwamy j.
j

2 4 3 1 4 3 3 6 7 8 7 9 2 6 7 6 5
18. i Szukamy
j

2 4 3 1 4 3 3 2 7 8 7 9 6 6 7 6 5
19. i Wymieniamy i przesuwamy j.
j

2 4 3 1 4 3 3 2 5 8 7 9 6 6 7 6 7 Brak dalszych elementów do wymiany. Piwot


20. ^ i wymieniamy z elementem na pozycji j-tej. Podział na

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 139 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

wymieniamy z elementem na pozycji j-tej. Podział na


Lewa partycja j Prawa partycja 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 j - 1. Prawa partycja zawiera elementy większe lub równe piwotowi i rozciąga się od
pozycji j + 1 do końca zbioru. Operacja podziału na partycje ma liniową klasę złożoności obliczeniowej - O(n).

Specyfikacja problemu
Sortuj_szybko(lewy, prawy)
Dane wejściowe
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
Dane wyjściowe
d[ ] - Zbiór zawierający elementy posortowane rosnąco
Zmienne pomocnicze
piwot - element podziałowy
i, j - indeksy, i, j Î C

Lista kroków
lewy + prawy
K01: i ← [ ]
2
K02: piwot ← d[i]; d[i] ← d[prawy]; j ← lewy
K03: Dla i = lewy, lewy + 1, ..., prawy - 1: wykonuj 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.

Schemat blokowy
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-ty element jest mniejszy od piwotu, to trafia on na
początek partycji - wymieniamy ze sobą elementy na pozycjach i-tej i j-tej.
Po tej operacji przesuwamy punkt podziałowy partycji j.
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
partycja prawa od pozycji j + 1 do pozycji prawy zawiera elementy
większe lub równe piwotowi.

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.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 140 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

Programy
Efekt uruchomienia programu
Sortowanie szybkie
------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
46 5 56 35 75 95 33 93 4 71 8 5 69 50 35 34 65 32 72 61
Po sortowaniu:
4 5 5 8 32 33 34 35 35 46 50 56 61 65 69 71 72 75 93 95

DevPascal
// Sortowanie Szybkie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// 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;
// 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('Nacisnij Enter...');
readln;
end.

Code::Blocks
// Sortowanie Szybkie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 141 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

//--------------------------------------------------------
#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;
// 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;
return 0;
}

Free Basic
' Sortowanie szybkie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' 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
' Sortujemy

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 142 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

Sortuj_szybko(1,N)
' Wyświetlamy wynik sortowania
Print "Po sortowaniu:": Print
For i = 1 To N: Print Using "####";d(i);: Next
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

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 I LO w Tarnowie - 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 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// 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;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 143 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

// 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>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Szybkie
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badanie algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania szybkiego w środowisku opisanym we wstępie. Program
testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie szybkie';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
procedure Sortuj_szybko(lewy, prawy : integer);
var
i,j : integer;
piwot,x : real;
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;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 144 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

function Sort : extended;


begin
QueryPerformanceCounter(addr(qpc1));
Sortuj_szybko(1,n);
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;
// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów
tnp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 145 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program


Nazwa: Sortowanie szybkie
-----------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000115 0.000118 0.000132 0.000136 0.000292
2000 0.000222 0.000227 0.000270 0.000284 0.000616
4000 0.000464 0.000479 0.000556 0.000569 0.001330
8000 0.001058 0.001079 0.001216 0.001225 0.002825
16000 0.002124 0.002185 0.002472 0.002549 0.006088
32000 0.004593 0.004465 0.005211 0.005104 0.012763
64000 0.009873 0.010195 0.010849 0.011224 0.027306
128000 0.020037 0.021543 0.022796 0.022578 0.057542
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów

(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)


(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania szybkiego
wyciągamy następujące wnioski:

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

Klasy złożoności obliczeniowej szacujemy następująco:


optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod. W przypadku tego algorytmu sortowania
nie jest to przypadek pesymistyczny.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n log n) O(n log n) O(n log n) O(n log n) O(n log n)
Sortowanie szybkie
tpo ≈ tod tpp ≈ tpk tnp ≈ 8tod
3
1. Wszystkie otrzymane czasy sortowania są proporcjonalne do iloczynu n log2 n, wnioskujemy zatem, iż klasa złożoności
obliczeniowej algorytmu sortowania szybkiego jest równa O(n log n).
2. Czasy sortowania dla poszczególnych przypadków są mniej więcej tego samego rzędu, zatem nie wystąpił tutaj przypadek
pesymistyczny (zwróć uwagę na istotny fakt - to, co dla jednego algorytmu jest przypadkiem pesymistycznym, dla innego
wcale nie musi takie być).
3. Czas sortowania zbiorów nieuporządkowanych jest wyraźnie dłuższy od czasów sortowania zbiorów uporządkowanych
częściowo.
4. Czas sortowania zbioru uporządkowanego oraz uporządkowanego odwrotnie jest praktycznie taki sam.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 146 / 209


Algorytmy Sortujące - Sortowanie szybkie 2014-10-03

8 5 5
Sortowanie przez scalanie ≈3 ≈ ≈ ≈ ≈1
Sortowanie szybkie
3 2 2
dobrze dobrze dobrze dobrze brak

5. Otrzymane wyniki potwierdzają, iż algorytm sortowania szybkiego jest najszybszym algorytmem sortującym. Jednakże w
przypadku ogólnym notujemy jedynie bardzo nieznaczny wzrost prędkości sortowania w stosunku do algorytmu sortowania
przez scalanie.
6. Ponieważ jak dotąd algorytm sortowania szybkiego jest najszybszym algorytmem sortującym, do dalszych porównań
czasów sortowania zastosujemy czasy uzyskane w tym algorytmie.

Zadania dla ambitnych


1. Spróbuj znaleźć przypadek pesymistyczny dla algorytmu sortowania szybkiego opisanego w tym rozdziale.
2. Przebadaj algorytmy sortowania szybkiego, w których piwot wybierany jest:
a. Na początku partycji
b. Na końcu partycji
c. W miejscu losowym wewnątrz partycji
3. Dlaczego czasy sortowania zbioru uporządkowanego i uporządkowanego odwrotnie są prawie równe?
4. Uzasadnij, iż algorytm sortowania szybkiego nie posiada cechy stabilności.
5. Wyszukaj w Internecie informację na temat algorytmu Introsort.

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0018.php 147 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie rozrzutowe
Distribution Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Sortowanie kubełkowe 1
Lista kroków Program w języku Pascal Listy
Program w języku C++ Sortowanie kubełkowe 2
Program w języku Basic Sortowanie przez zliczanie
Program w języku JavaScript Sortowanie pozycyjne

Algorytm
Wszystkie opisane dotychczas algorytmy sortujące opierają się na sprawdzaniu uporządkowania zbioru, które polega na
porównywaniu elementów. Udowodniono, iż barierą efektywności takich algorytmów w przypadku ogólnym (sortowanie zbioru o
losowym rozkładzie elementów) jest klasa złożoności obliczeniowej O(n log n). Zachodzi zatem naturalne pytanie: czy istnieją
inne sposoby sortowania o niższej klasie złożoności obliczeniowej?
Na samym początku III części "Sztuki Programowania Komputerów" prof. Donald Knuth opisuje znany od dawna sposób
porządkowania talii kart.
Ustalmy kolejność kolorów kart wg ich starszeństwa (pierwszy pik, ostatni trefl):

♠ - pik
♥ - kier
♦ - karo
♣ - trefl

Teraz ustalmy kolejność figur (dla uproszczenia przyjmujemy talię z 24 kart, chociaż algorytm jest również poprawny dla pełnej talii
52 kart):

A - as
K - król
D - dama
W - walet
T - dziesiątka
9 - dziewiątka

Przykład:
Załóżmy, iż mamy potasowaną losowo talię 24 kart:

♥D ♦K ♣K ♥9 ♠D ♣W ♠A ♥K ♣9 ♦T ♦A ♠K ♥T ♠W ♥A ♣D ♦D ♥W ♠9 ♣A ♦9 ♦W ♠T ♣T

Chcemy je posortować szybko tak, aby najpierw występowały piki, później kiery, kara a na końcu trefle. W obrębie
każdego koloru karty powinny być uporządkowane wg podanej powyżej kolejności. Postępujemy tak:
Najpierw kolejne karty układamy na 6 stosów wg figur (kolorem się chwilowo nie przejmujemy):

A K D W T 9
♠A ♦K ♥D ♣W ♦T ♥9
♦A ♣K ♠D ♠W ♥T ♣9
♥A ♥K ♣D ♥W ♠T ♠9
♣A ♠K ♦D ♦W ♣T ♦9

Poszczególne stosy łączymy ze sobą w talie kart - karty pobieramy z kupek w tej samej kolejności, w której były na
nie wstawiane (u nas wstawianie rozpoczęliśmy od góry, zatem również od góry rozbieramy każdą z kupek):

♠A ♦A ♥A ♣A ♦K ♣K ♥K ♠K ♥D ♠D ♣D ♦D ♣W ♠W ♥W ♦W ♦T ♥T ♠T ♣T ♥9 ♣9 ♠9 ♦9

W drugim kroku otrzymaną talie rozkładamy na 4 stosy wg kolorów:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 148 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

♠ ♥ ♦ ♣
♠A ♥A ♦A ♣A
♠K ♥K ♦K ♣K
♠D ♥D ♦D ♣D
♠W ♥W ♦W ♣W
♠T ♥T ♦T ♣T
♠9 ♥9 ♦9 ♣9

Teraz wystarczy połączyć ze sobą otrzymane stosy w jedną talię 24 kart:

♠A ♠K ♠D ♠W ♠T ♠9 ♥A ♥K ♥D ♥W ♥T ♥9 ♦A ♦K ♦D ♦W ♦T ♦9 ♣A ♣K ♣D ♣W ♣T ♣9

Talia kart jest posortowana.

Lista kroków
K01: Przygotuj miejsce na tyle stosów, ile figur mogą mieć karty. Pierwszy stos będzie dla najstarszej karty, a ostatni dla
najmłodszej.
K02: Rozdziel poszczególne karty na przygotowane wcześniej stosy wg figur - np. wszystkie asy idą do stosu asów, króle idą do
stosu króli, itd.
K03: Złóż ze sobą karty w kolejnych stosach poczynając od stosu zawierającego najstarsze figury, a kończąc na stosie z
najmłodszymi figurami.
K04: Przygotuj miejsce dla czterech stosów kolorów. Stosy powinny być ułożone w kolejności starszeństwa kolorów, np. piki,
kiery, karo, trefle.
K05: Rozdziel karty na poszczególne stosy wg ich kolorów.
K06: Złóż ze sobą karty z kolejnych stosów poczynając od stosu zawierającego karty w najstarszym kolorze a kończąc na
stosie z kartami w najmłodszym kolorze. Talia zostanie uporządkowana
K07: Zakończ algorytm

Zwróć uwagę, iż przedstawiona metoda w ogóle nie porównuje elementów ze sobą. Elementy trafiają do odpowiednich stosów (są
rozrzucane - stąd nazwa sortowanie rozrzutowe) na podstawie swojej wartości, a nie na podstawie ich relacji z innymi elementami
zbioru. Dzięki takiemu podejściu zmieniona zostaje klasa czasowej złożoności obliczeniowej:

Pierwsza operacja - rozłożenie n elementów na m kupek ma klasę złożoności O(n).


Druga operacja - złączenie m kupek w n elementów ma klasę złożoności O(m).

Sumarycznie cały algorytm będzie posiadał klasę złożoności O(n + m). Jest to klasa liniowa, zatem sortowanie będzie bardzo
szybkie. Co więcej, algorytm tego typu nie posiada przypadku pesymistycznego - czas sortowania każdego zbioru danych jest
porównywalny. Mankament tego rozwiązania stanowi dodatkowe zapotrzebowanie na pamięć O(n) - musimy zarezerwować
komórki na elementy przechowywane w stosach.

Programy
W programach wykorzystuje się opisany algorytm sortowania kart, który może stanowić część większego programu gry w karty (to
już pozostawiamy inwencji czytelnika). Od razu zastrzegam, iż problem sortowania kart rozwiązuje się o wiele prościej, jednakże
tutaj chodzi o przedstawienie sposobu realizacji opisanego algorytmu. Zatem program ma raczej wartość dydaktyczną niż
użytkową.

Efekt uruchomienia programu


♠ KD987
♥ D83
♦ D54
♣ K3
♠ A3 ♠ 652
♥ KW4 ♥ T96
♦ W973 ♦ A86
♣ D764 ♣ W852
♠ WT4
♥ A752
♦ KT2
♣ AT9

DevPascal
// Sortowanie Kart
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program skart;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 149 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

uses Crt;
// Definicje typów danych
//--------------------------------------------------------
type
TKolor = (K_PIK,K_KIER,K_KARO,K_TREFL,K_PUSTY);
TFigura = (F_A,F_K,F_D,F_W,F_10,F_9,F_8,F_7,F_6,F_5,F_4,F_3,F_2,F_0);
TKarta = record
Kolor : TKolor;
Figura : TFigura;
end;
// Definicje zmiennych globalnych
//--------------------------------------------------------
var
talia : array[1..52] of TKarta;
gracz : array[1..4,1..13] of TKarta;
// Definicje procedur i funkcji
//--------------------------------------------------------
// Procedura inicjuje talię kart
//--------------------------------------------------------
procedure Inicjuj_talie;
var
i : integer;
k : TKolor;
f : TFigura;
begin
k := K_PIK; f := F_A;
for i := 1 to 52 do
begin
talia[i].Kolor := k; talia[i].Figura := f;
inc(f);
if f = F_0 then
begin
inc(k); f := F_A;
end
end;
end;
// Procedura tasuje talię kart
//--------------------------------------------------------
procedure Tasuj_talie;
var
i,a,b : integer;
x : TKarta;
begin
for i := 1 to 1000 do
begin
a := 1 + random(52); b := 1 + random(52);
x := talia[a]; talia[a] := talia[b]; talia[b] := x;
end;
end;
// Procedura rozdaje karty poszczególnym graczom
//--------------------------------------------------------
procedure Rozdaj_karty;
var
i,j,k : integer;
begin
k := 1;
for i := 1 to 4 do
for j := 1 to 13 do
begin
gracz[i,j] := talia[k];
inc(k);
end;
end;
// Procedura sortuje karty gracza wg kolorów i figur
//--------------------------------------------------------
procedure Sortuj_karty(g : integer);
var
karty : array[0..3,0..12] of TKarta;
lfig : array[TFigura] of integer;
lkol : array[TKolor] of integer;
f : TFigura;
k : TKolor;
i,j : integer;
begin
// Ustawiamy liczniki figur
for f := F_A to F_2 do lfig[f] := 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// figur wg figury
for i := 1 to 13 do
begin
f := gracz[g,i].Figura;
karty[lfig[f],ord(f)] := gracz[g,i];

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 150 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

inc(lfig[f]);
end;
// Przeglądamy tablicę figur pobierając z niej karty do ręki gracza
i := 1;
for f := F_A to F_2 do
for j := 0 to lfig[f] - 1 do
begin
gracz[g,i] := karty[j,ord(f)];
inc(i);
end;
// Ustawiamy liczniki kolorów
for k := K_PIK to K_TREFL do lkol[k] := 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// kolorów wg koloru karty
for i := 1 to 13 do
begin
k := gracz[g,i].Kolor;
karty[ord(k),lkol[k]] := gracz[g,i];
inc(lkol[k]);
end;
// Przeglądamy tablicę kolorów pobierając z niej karty do ręki gracza
i := 1;
for k := K_PIK to K_TREFL do
for j := 0 to lkol[k] - 1 do
begin
gracz[g,i] := karty[ord(k),j];
inc(i);
end;
end;
// Procedura wyświetla karty gracza wg jego numeru:
// 1 : gracz u góry (15,1)
// 2 : gracz po prawej (30,6)
// 3 : gracz u dołu (15,11)
// 4 : gracz po lewej (1,6)
// okna konsoli. Wydruk zajmuje 4 wiersze, w każdym do 15 znaków.
// Figurę 10 wyświetlamy jako T - każda karta powinna zajmować jeden
// znak, a zapis 10 wymaga dwóch znaków.
//--------------------------------------------------------
procedure Wyswietl_karty(g : integer);
const
kolory : string[4] = (#6#3#4#5);
figury : string[13] = ('AKDWT98765432');
px : array[1..4] of integer = (15,30,15,1);
py : array[1..4] of integer = (1,6,11,6);
var
i : integer;
k : TKolor;
begin
for k := K_PIK to K_TREFL do
begin
gotoXY(px[g], py[g] + ord(k));
write(kolory[1 + ord(k)],' ');
for i := 1 to 13 do
if gracz[g,i].Kolor = k then
write(figury[1 + ord(gracz[g,i].Figura)]);
end;
end;
//---------------
// Program główny
//---------------
var
i : integer;
begin
Randomize;
Inicjuj_talie;
Tasuj_talie;
Rozdaj_karty;
for i := 1 to 4 do
begin
Sortuj_karty(i);
Wyswietl_karty(i);
end;
gotoXY(1,16); writeln('Gotowe. Nacisnij klawisz Enter...');
readln;
end.

Code::Blocks
// Sortowanie Kart
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 151 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <time.h>
using namespace std;
// Definicje typów danych
//--------------------------------------------------------
enum TKolor {K_PIK,K_KIER,K_KARO,K_TREFL,K_PUSTY};
enum TFigura {F_A,F_K,F_D,F_W,F_10,F_9,F_8,F_7,F_6,F_5,F_4,F_3,F_2,F_0};
struct TKarta
{
TKolor Kolor;
TFigura Figura;
};

// Definicja operatora ++ dla typów TKolor i TFigura


//---------------------------------------------------------
inline TKolor operator++(TKolor &rs,int)
{
return rs = (TKolor)(rs + 1);
}
inline TFigura operator++(TFigura &rs,int)
{
return rs = (TFigura)(rs + 1);
}
// Deklaracje zmiennych globalnych
//--------------------------------------------------------
TKarta talia[52];
TKarta gracz[4][13];
// Definicje procedur i funkcji
//--------------------------------------------------------
// Procedura ustawia pozycję wydruku w oknie konsoli
//--------------------------------------------------------
void gotoXY(int x, int y)
{
COORD p;
HANDLE h;
h = GetStdHandle(STD_OUTPUT_HANDLE);
p.X = x - 1; p.Y = y - 1;
SetConsoleCursorPosition(h,p);
}
// Procedura inicjuje talię kart
//--------------------------------------------------------
void Inicjuj_talie()
{
int i;
TKolor k;
TFigura f;
k = K_PIK; f = F_A;
for(i = 0; i < 52; i++)
{
talia[i].Kolor = k; talia[i].Figura = f;
f++;
if(f == F_0)
{
k++; f = F_A;
}
}
}
// Procedura tasuje talię kart
//--------------------------------------------------------
void Tasuj_talie()
{
int i,a,b;
for(i = 0; i < 1000; i++)
{
a = rand() % 52; b = rand() % 52;
swap(talia[a], talia[b]);
}
}
// Procedura rozdaje karty poszczególnym graczom
//--------------------------------------------------------
void Rozdaj_karty()
{
int i,j,k;
k = 0;
for(i = 0; i < 4; i++)
for(j = 0; j < 13; j++) gracz[i][j] = talia[k++];
}
// Procedura sortuje karty gracza wg kolorów i figur

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 152 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

//--------------------------------------------------------
void Sortuj_karty(int g)
{
TKarta karty[4][13];
int lfig[13], lkol[4],i,j;
TFigura f;
TKolor k;
// Ustawiamy liczniki figur
for(f = F_A; f < F_0; f++) lfig[f] = 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// figur wg figury
for(i = 0; i < 13; i++)
{
f = gracz[g][i].Figura;
karty[lfig[f]++][f] = gracz[g][i];
}
// Przeglądamy tablicę figur pobierając z niej karty do ręki gracza
i = 0;
for(f = F_A; f < F_0; f++)
for(j = 0; j < lfig[f]; j++) gracz[g][i++] = karty[j][f];
// Ustawiamy liczniki kolorów
for(k = K_PIK; k < K_PUSTY; k++) lkol[k] = 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// kolorów wg koloru karty
for(i = 0; i < 13; i++)
{
k = gracz[g][i].Kolor;
karty[k][lkol[k]++] = gracz[g][i];
}
// Przeglądamy tablicę kolorów pobierając z niej karty do ręki gracza
i = 0;
for(k = K_PIK; k < K_PUSTY; k++)
for(j = 0; j < lkol[k]; j++) gracz[g][i++] = karty[k][j];
}
// Procedura wyświetla karty gracza wg jego numeru:
// 1 : gracz u góry (15,1)
// 2 : gracz po prawej (30,6)
// 3 : gracz u dołu (15,11)
// 4 : gracz po lewej (1,6)
// okna konsoli. Wydruk zajmuje 4 wiersze, w każdym do 15 znaków.
// Figurę 10 wyświetlamy jako T - każda karta powinna zajmować jeden
// znak, a zapis 10 wymaga dwóch znaków.
//--------------------------------------------------------
void Wyswietl_karty(int g)
{
const char kolory[4] = {6,3,4,5};
const char * figury = "AKDWT98765432";
const int px[4] = {15,30,15,1};
const int py[4] = {1,6,11,6};
int i;
TKolor k;
for(k = K_PIK; k < K_PUSTY; k++)
{
gotoXY(px[g],py[g] + k);
cout << kolory[k] << " ";
for(i = 0; i < 13; i++)
if(gracz[g][i].Kolor == k) cout << figury[gracz[g][i].Figura];
}
}
//---------------
// Program główny
//---------------
int main()
{
int i;
srand((unsigned)time(NULL));
Inicjuj_talie();
Tasuj_talie();
Rozdaj_karty();
for(i = 0; i < 4; i++)
{
Sortuj_karty(i); Wyswietl_karty(i);
}
gotoXY(1,16);
return 0;
}

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 153 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

Free Basic
' Sortowanie Kart
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
' Definicje typów danych
'--------------------------------------------------------
Option Explicit
Enum TKolor
K_PIK
K_KIER
K_KARO
K_TREFL
K_PUSTY
End Enum
Enum TFigura
F_A
F_K
F_D
F_W
F_10
F_9
F_8
F_7
F_6
F_5
F_4
F_3
F_2
F_0
End Enum
Type TKarta
Kolor As TKolor
Figura As TFigura
End Type
' Definicje zmiennych globalnych
'--------------------------------------------------------
Dim Shared talia(52) As TKarta
Dim Shared gracz(4,13) As TKarta
' Definicje procedur i funkcji
'--------------------------------------------------------
' Procedura inicjuje talię kart
'--------------------------------------------------------
Declare Sub Inicjuj_talie()
Sub Inicjuj_talie()
Dim i As Integer
Dim k As TKolor
Dim f As TFigura
k = K_PIK: f = F_A
For i = 1 To 52
talia(i).Kolor = k: talia(i).Figura = f
f += 1
If f = F_0 Then
k += 1: f = F_A
End If
Next
End Sub
' Procedura tasuje talię kart
'--------------------------------------------------------
Declare Sub Tasuj_talie()
Sub Tasuj_talie()
Dim As Integer i,a,b
For i = 1 To 1000
a = 1 + Int(Rnd(1) * 52): b = 1 + Int(Rnd(1) * 52)
Swap talia(a), talia(b)
Next
End Sub
' Procedura rozdaje karty poszczególnym graczom
'--------------------------------------------------------
Declare Sub Rozdaj_karty()
Sub Rozdaj_karty()

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 154 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

Dim As Integer i,j,k


k = 1
For i = 1 To 4
For j = 1 To 13
gracz(i,j) = talia(k)
k += 1
Next
Next
End Sub
' Procedura sortuje karty gracza wg kolorów i figur
'--------------------------------------------------------
Declare Sub Sortuj_karty(Byval g As Integer)
Sub Sortuj_karty(Byval g As Integer)
Dim karty(0 To 3,0 To 12) As TKarta
Dim As Integer lfig(0 To 12),lkol(0 To 3),i,j
Dim f As TFigura
Dim k As TKolor
' Ustawiamy liczniki figur
For f = F_A To F_2: lfig(f) = 0: Next
' Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
' figur wg figury
For i = 1 To 13
f = gracz(g,i).Figura
karty(lfig(f),f) = gracz(g,i)
lfig(f) += 1
Next
' Przeglądamy tablicę figur pobierając z niej karty do ręki gracza
i = 1
For f = F_A To F_2
For j = 0 To lfig(f) - 1
gracz(g,i) = karty(j,f)
i += 1
Next
Next
' Ustawiamy liczniki kolorów
For k = K_PIK To K_TREFL: lkol(k) = 0: Next
' Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
' kolorów wg koloru karty
For i = 1 To 13
k = gracz(g,i).Kolor
karty(k,lkol(k)) = gracz(g,i)
lkol(k) += 1
Next
' Przeglądamy tablicę kolorów pobierając z niej karty do ręki gracza
i = 1
For k = K_PIK To K_TREFL
For j = 0 To lkol(k) - 1
gracz(g,i) = karty(k,j)
i += 1
Next
Next
End Sub
' Procedura wyświetla karty gracza wg jego numeru:
' 1 : gracz u góry (15,1)
' 2 : gracz po prawej (30,6)
' 3 : gracz u dołu (15,11)
' 4 : gracz po lewej (1,6)
' okna konsoli. Wydruk zajmuje 4 wiersze, w każdym do 15 znaków.
' Figurę 10 wyświetlamy jako T - każda karta powinna zajmować jeden
' znak, a zapis 10 wymaga dwóch znaków.
'--------------------------------------------------------
Declare Sub Wyswietl_karty(Byval g As Integer)
Sub Wyswietl_karty(Byval g As Integer)
Dim kolory As String * 4
Dim figury As String * 13
Dim px(1 To 4) As Integer => {15,30,15,1}
Dim py(1 To 4) As Integer => {1,6,11,6}
Dim i As Integer, k As TKolor
kolory = CHR$(6) + CHR$(3) + CHR$(4) + CHR$(5)
figury = "AKDWT98765432"
For k = K_PIK To K_TREFL
Locate py(g) + k, px(g)
Print MID$(kolory, 1 + k, 1);" ";
For i = 1 To 13
If gracz(g,i).Kolor = k Then

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 155 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

Print MID$(figury, 1 + gracz(g,i).Figura, 1);


End If
Next
Next
End Sub
'---------------
' Program główny
'---------------
Dim i As Integer
Randomize
Inicjuj_talie()
Tasuj_talie()
Rozdaj_karty()
For i = 1 To 4
Sortuj_karty(i)
Wyswietl_karty(i)
Next
Locate 16,1
Print "Gotowe. Nacisnij dowolny klawisz..."
Sleep
End

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="frmdistsort">
<h3 style="text-align: center">Sortowanie Kart</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Sortuj" name="B1">
</p>
<div align="center">
<table border="0" id="table194" cellpadding="8"
style="border-collapse: collapse" bgcolor="#FFFFFF">
<tr>
<td>&nbsp;</td>
<td><span id="tg1">.</span></td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span id="tg4">.</span></td>
<td bgcolor="#009900" style="border: 4px solid #006600">&nbsp;</td>
<td><span id="tg2">.</span></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><span id="tg3">.</span></td>
<td>&nbsp;</td>
</tr>
</table>
</div>
</form>
<script language="javascript">
// Sortowanie Kart
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
// Deklaracje zmiennych globalnych
//--------------------------------------------------------
var talia = new Array();
var gracz = new Array()
var i,j;
for(i = 0; i < 52; i++) talia[i] = new Object();
for(i = 0; i < 4; i++)
{
gracz[i] = new Array();
for(j = 0; j < 13; j++) gracz[i][j] = new Object();
}
// Definicje procedur i funkcji
//--------------------------------------------------------
// Procedura inicjuje talię kart
//--------------------------------------------------------
function Inicjuj_talie()

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 156 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

{
var i,k,f
k = f = 0;
for(i = 0; i < 52; i++)
{
talia[i].Kolor = k; talia[i].Figura = f;
f++;
if(f == 13)
{
k++; f = 0;
}
}
}
// Procedura tasuje talię kart
//--------------------------------------------------------
function Tasuj_talie()
{
var i,a,b;
var x = new Object();
for(i = 0; i < 1000; i++)
{
a = Math.floor(Math.random() * 52); b = Math.floor(Math.random() * 52);
x = talia[a]; talia[a] = talia[b]; talia[b] = x;
}
}
// Procedura rozdaje karty poszczególnym graczom
//--------------------------------------------------------
function Rozdaj_karty()
{
var i,j,k;
k = 0;
for(i = 0; i < 4; i++)
for(j = 0; j < 13; j++) gracz[i][j] = talia[k++];
}
// Procedura sortuje karty gracza wg kolorów i figur
//--------------------------------------------------------
function Sortuj_karty(g)
{
var karty = new Array();
var lfig = new Array()
var lkol = new Array()
var i,j,f,k;
for(i = 0; i < 4; i++)
{
karty[i] = new Array();
for(j = 0; j < 13; j++) karty[i][j] = new Object();
}
// Ustawiamy liczniki figur
for(f = 0; f < 13; f++) lfig[f] = 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// figur wg figury
for(i = 0; i < 13; i++)
{
f = gracz[g][i].Figura;
karty[lfig[f]++][f] = gracz[g][i];
}
// Przeglądamy tablicę figur pobierając z niej karty do ręki gracza
i = 0;
for(f = 0; f < 13; f++)
for(j = 0; j < lfig[f]; j++) gracz[g][i++] = karty[j][f];
// Ustawiamy liczniki kolorów
for(k = 0; k < 4; k++) lkol[k] = 0;
// Przeglądamy rękę gracza i umieszczamy kolejne karty w tablicy
// kolorów wg koloru karty
for(i = 0; i < 13; i++)
{
k = gracz[g][i].Kolor;
karty[k][lkol[k]++] = gracz[g][i];
}
// Przeglądamy tablicę kolorów pobierając z niej karty do ręki gracza
i = 0;
for(k = 0; k < 4; k++)
for(j = 0; j < lkol[k]; j++) gracz[g][i++] = karty[k][j];
}
// Procedura wyświetla karty gracza wg jego numeru:
// 0 : gracz u góry
// 1 : gracz po prawej

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 157 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

// 2 : gracz u dołu
// 3 : gracz po lewej
// okna konsoli. Wydruk zajmuje 4 wiersze, w każdym do 15 znaków.
// Figurę 10 wyświetlamy jako T - każda karta powinna zajmować jeden
// znak, a zapis 10 wymaga dwóch znaków.
//--------------------------------------------------------
function Wyswietl_karty(g)
{
var kolory = new Array("&#9824;","&#9829;","&#9830;","&#9827;");
var figury = "AKDWT98765432";
var i,k,t;
t = "";
for(k = 0; k < 4; k++)
{
switch(k)
{
case 0:
case 3: t += "<font color='black'>"; break;
case 1:
case 2: t += "<font color='red'>"; break;
}
t += kolory[k] + " ";
for(i = 0; i < 13; i++)
if(gracz[g][i].Kolor == k) t += figury.charAt(gracz[g][i].Figura);
t += "</font><br>"
}
g++;
document.getElementById("tg" + g).innerHTML = t;
}
//---------------
// Program główny
//---------------
function main()
{
var i;
Inicjuj_talie();
Tasuj_talie();
Rozdaj_karty();
for(i = 0; i < 4; i++)
{
Sortuj_karty(i); Wyswietl_karty(i);
}
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Kart
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj

. .

Zobacz również na:


Sortowanie kubełkowe 1 | Listy | Sortowanie kubełkowe 2 | Sortowanie przez zliczanie | Sortowanie pozycyjne

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany
Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 158 / 209


Algorytmy Sortujące - Sortowanie rozrzutowe 2014-10-03

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0019.php 159 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie kubełkowe
Bucket Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Sortowanie rozrzutowe
Specyfikacja problemu Program w języku Pascal Listy
Lista kroków Program w języku C++ Sortowanie kubełkowe 2
Schemat blokowy Program w języku Basic Sortowanie przez zliczanie
Program w języku JavaScript Sortowanie pozycyjne

Algorytm
Opisany w tym rozdziale algorytm sortowania kubełkowego pozwala sortować zbiory liczb całkowitych - najlepiej o dużej ilości
elementów, lecz o małym zakresie wartości. Zasada działania jest następująca:

1. Określamy zakres wartości, jakie mogą przyjmować elementy sortowanego zbioru. Niech wmin oznacza najmniejszą
wartość, a wmax niech oznacza wartość największą.
2. Dla każdej możliwej wartości przygotowujemy kubełek-licznik, który będzie zliczał ilość wystąpień tej wartości w
sortowanym zbiorze. Liczba liczników jest równa (wmax - wmin + 1). Każdy licznik jest początkowo ustawiony na wartość
zero.
3. Przeglądamy kolejno elementy zbioru od pierwszego do ostatniego. Dla każdego elementu zbioru zwiększamy o jeden
zawartość licznika o numerze równym wartości elementu. Na przykład, jeśli kolejny element zbioru ma wartość 3, to
zwiększamy licznik o numerze 3. W efekcie po przeglądnięciu wszystkich elementów zbioru liczniki będą zawierały ilość
wystąpień każdej z możliwych wartości. Jeśli dany licznik zawiera 0, to wartość równa numerowi licznika w zbiorze nie
występuje. Inaczej wartość ta występuje tyle razy, ile wynosi zawartość jej licznika.
4. Przeglądamy kolejne liczniki zapisując do zbioru wynikowego ich numery tyle razy, ile wynosi ich zawartość. Zbiór
wyjściowy będzie posortowany.

Przykład:
Dla przykładu posortujemy opisaną wyżej metodą zbiór { 2 6 4 3 8 7 2 5 7 9 3 5 2 6 }.
Najpierw określamy zakres wartości elementów (w tym celu możemy na przykład wyszukać w zbiorze element
najmniejszy i największy). U nas zakres wynosi:

wmin = 2, wmax = 9

Potrzebujemy zatem:

wmax - wmin + 1 = 9 - 2 + 1 = 8 liczników.

Liczniki ponumerujemy zgodnie z wartościami, które będą zliczały:

[2] [3] [4] [5] [6] [7] [8] [9]

Na początku sortowania wszystkie liczniki mają stan zero:

[2:0] [3:0] [4:0] [5:0] [6:0] [7:0] [8:0] [9:0]

Teraz przeglądamy kolejne elementy zbioru zliczając ich wystąpienia w odpowiednich licznikach:

{26438725793526}
[2:3] [3:2] [4:1] [5:2] [6:2] [7:2] [8:1] [9:1]

Zapis [2:3] oznacza, iż licznik numer 2 zawiera liczbę 3, a to z kolei oznacza, iż liczba 2 pojawiła się w zbiorze 3
razy. Przeglądamy kolejne liczniki począwszy od licznika o najmniejszym numerze (w przypadku sortowania
malejącego przeglądanie rozpoczynamy od licznika o największym numerze) i zapisujemy do zbioru wynikowego
tyle razy numer licznika, ile wynosi jego zawartość:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 160 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

[2:3] [3:2] [4:1] [5:2] [6:2] [7:2] [8:1] [9:1]


{22233455667789}

Uwaga, pułapka:
Algorytm wymaga ponumerowania liczników kolejno od wmin do wmax. Niektóre języki
programowania (np. C++) nie pozwalają numerować dowolnie elementów tablic - zwykle numeracja
rozpoczyna się od liczby 0. W takich przypadkach musimy dokonać przeliczenia indeksu licznika,
na zliczaną przezeń wartość i na odwrót. Wzory są na szczęście bardzo proste:
Mamy wartość w i chcemy znaleźć indeks licznika, który ją zlicza:
indeks ← w - wmin
Mamy indeks licznika i chcemy znaleźć zliczaną wartość w:
w ← indeks + wmin

Specyfikacja problemu
Dane wejściowe
d[ ] - sortowany zbiór liczb całkowitych. Indeksy elementów rozpoczynają się od 1.
n - liczba elementów w zbiorze, n Î N
wmin - minimalna wartość elementów zbioru, wmin Î C
wmax - maksymalna wartość elementów zbioru, wmax Î C

Dane wyjściowe
d[ ] - posortowany zbiór liczb całkowitych.
Zmienne pomocnicze
lw [ ] - tablica liczników wartości o indeksach od wmin do wmax. Każdy licznik przechowuje liczbę całkowitą
i, j - zmienne licznikowe pętli, i,j Î C

Lista kroków
K01: Dla i = wmin , wmin + 1,...,wmax: wykonuj lw [i] ← 0
K02: Dla i = 1,2,...,n: wykonuj lw [ d[i] ] ← lw [ d[i] ] + 1
K03: j ← 1
K04: Dla i = wmin , wmin + 1,...,wmax: wykonuj K05
K05: Dopóki lw [i] > 0 wykonuj:
d[j] ← i
lw [i] ← lw [i] - 1
j ←j + 1
K06: Zakończ

Algorytm ma klasę czasowej złożoności obliczeniowej O(m + n), gdzie m oznacza ilość możliwych wartości, które mogą
przyjmować elementy zbioru, a n to ilość sortowanych elementów. Jeśli m jest małe w porównaniu z n (sortujemy dużo elementów
o małym zakresie wartości), to na czas sortowania będzie miała wpływ głównie ilość elementów n i klasa złożoności uprości się
do postaci O(n). Dzieje się tak dlatego, iż przy równomiernym rozkładzie dużej ilości elementów o małym zakresie wartości
liczniki będą równomiernie zapełnione (stan każdego licznika będzie dążył do [n/m]). Zatem algorytm wykona:

1. m operacji zerowania liczników - czas pomijalnie mały i przy dużym n nie wpływa istotnie na klasę algorytmu.
2. n operacji zwiększania liczników
3. n operacji przesłania numerów liczników do zbioru wynikowego - ilość pustych liczników będzie dążyła do zera.
W sytuacji odwrotnej, gdy sortujemy mało elementów o dużym zakresie wartości klasa złożoności zredukuje się z kolei do O(m) -
spróbuj uzasadnić ten wynik samemu na podstawie analizy działania poszczególnych fragmentów algorytmu.

Schemat blokowy
Algorytm realizujemy w czterech pętlach.
Pętla nr 1 zeruje kolejne liczniki lw[ ].
W pętli nr 2 przeglądamy kolejne elementy zbioru od pierwszego do ostatniego. Dla
każdego elementu zwiększamy licznik o numerze równym wartości elementu. Po
zakończeniu tej pętli liczniki zawierają liczbę wystąpień poszczególnych wartości
elementów w sortowanym zbiorze.
Zmienna j służy do umieszczania w zbiorze wyjściowym kolejnych elementów.
Umieszczanie rozpoczniemy od początku zbioru, dlatego zmienne ta przyjmuje wartość 1.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 161 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

Pętla nr 3 przegląda kolejne liczniki. Jeśli zawartość danego licznika jest większa od zera,
to pętla nr 4 umieści w zbiorze wyjściowym odpowiednią ilość numerów licznika, które
odpowiadają zliczonym wartościom elementów ze zbioru wejściowego.
Po zakończeniu pętli nr 3 elementy w zbiorze wyjściowym są posortowane. Kończymy
algorytm.

Programy
Program sortuje 80 liczb z zakresu od -99 do 99.

Efekt uruchomienia programu


Sortowanie kubelkowe
----------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
-99 45 96 -41 93 86 52 -30 77 -28 -44 -19 40 65 -28 96 90 -39 52 -49
-33 35 -31 9 -66 2 -56 62 60 -23 31 47 27 -70 38 85 39 49 -15 12
-84 60 -46 -58 -49 -47 -50 12 -53 8 -70 2 4 72 42 11 76 84 24 36
71 71 -2 -27 -19 23 -43 -59 84 -67 -96 -83 -40 -60 6 -10 -30 -78 -76 -48
Po sortowaniu:
-99 -96 -84 -83 -78 -76 -70 -70 -67 -66 -60 -59 -58 -56 -53 -50 -49 -49 -48 -47
-46 -44 -43 -41 -40 -39 -33 -31 -30 -30 -28 -28 -27 -23 -19 -19 -15 -10 -2 2
2 4 6 8 9 11 12 12 23 24 27 31 35 36 38 39 40 42 45 47
49 52 52 60 60 62 65 71 71 72 76 77 84 84 85 86 90 93 96 96

DevPascal
// Sortowanie Kubełkowe
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program bucketsort;
const WMIN = -99;
const WMAX = 99;
const N = 80;
var
d : array[1..N] of integer;
lw : array[WMIN..WMAX] of integer;
i,j : integer;
begin
writeln(' Sortowanie kubelkowe ');
writeln('----------------------');
writeln('(C)2005 Jerzy Walaszek');
writeln;
// tworzymy zbiór wejściowy do sortowania
randomize;
for i := 1 to N do d[i] := WMIN + random(WMAX - WMIN + 1);
// wyświetlamy zawartość zbioru przed sortowaniem
writeln('Przed sortowaniem:');
writeln;
for i := 1 to N do write(d[i]:4);
writeln;
// sortujemy
// najpierw zerujemy liczniki
for i := WMIN to WMAX do lw[i] := 0;
// zliczamy w odpowiednich licznikach wystąpienia
// wartości elementów sortowanego zbioru
for i := 1 to N do inc(lw[d[i]]);
// zapisujemy do zbioru wynikowego numery niezerowych liczników
// tyle razy, ile wynosi ich zawartość

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 162 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

j := 1;
for i := WMIN to WMAX do
while lw[i] > 0 do
begin
d[j] := i; inc(j); dec(lw[i]);
end;
// wyświetlamy zawartość zbioru po sortowaniu
writeln('Po sortowaniu:');
writeln;
for i := 1 to N do write(d[i]:4);
// koniec
writeln;
writeln('Gotowe. Nacisnij klawisz ENTER...');
readln;
end.

Code::Blocks
// Sortowanie Kubełkowe
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int WMIN = -99;
const int WMAX = 99;
const int N = 80;
int d[N],lw[WMAX - WMIN + 1],i,j;
cout << " Sortowanie kubelkowe \n"
"----------------------\n"
"(C)2005 Jerzy Walaszek\n\n";
// tworzymy zbiór wejściowy do sortowania
srand((unsigned)time(NULL));
for(i = 0; i < N; i++) d[i] = WMIN + rand() % (WMAX - WMIN + 1);
// wyświetlamy zawartość zbioru przed sortowaniem
cout << "Przed sortowaniem:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
cout << endl;
// sortujemy
// najpierw zerujemy liczniki
for(i = WMIN; i <= WMAX; i++) lw[i - WMIN] = 0;
// zliczamy w odpowiednich licznikach wystąpienia
// wartości elementów sortowanego zbioru
for(i = 0; i < N; i++) lw[d[i] - WMIN]++;
// zapisujemy do zbioru wynikowego numery niezerowych liczników
// tyle razy, ile wynosi ich zawartość
j = 0;
for(i = WMIN; i <= WMAX; i++) while(lw[i - WMIN]--) d[j++] = i;
// wyświetlamy zawartość zbioru po sortowaniu
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(4) << d[i];
// koniec
cout << endl;
return 0;
}

Free Basic
' Sortowanie Kubełkowe
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 163 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

Const WMIN = -99


Const WMAX = 99
Const N = 80
Dim As Integer d(N),lw(WMIN To WMAX),i,j
Print " Sortowanie kubelkowe "
Print "----------------------"
Print "(C)2005 Jerzy Walaszek"
Print
' tworzymy zbiór wejściowy do sortowania
Randomize
For i = 1 To N: d(i) = WMIN + Int(Rnd(1) * (WMAX - WMIN + 1)): Next
' wyświetlamy zawartość zbioru przed sortowaniem
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
' sortujemy
' najpierw zerujemy liczniki
For i = WMIN To WMAX: lw(i) = 0: Next
' zliczamy w odpowiednich licznikach wystąpienia
' wartości elementów sortowanego zbioru
For i = 1 To N: lw(d(i)) += 1: Next
' zapisujemy do zbioru wynikowego numery niezerowych liczników
' tyle razy, ile wynosi ich zawartość
j = 1
For i = WMIN To WMAX
While lw(i) > 0
d(j) = i: j += 1: lw(i) -= 1
Wend
Next
' wyświetlamy zawartość zbioru po sortowaniu
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
' koniec
Print
Print "Gotowe. Nacisnij dowolny klawisz..."
Sleep
End

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="frmbucketsort">
<h3 style="text-align: center">Sortowanie Kubełkowe</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Kubełkowe
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
function main()
{
var WMIN = -99;
var WMAX = 99;
var N = 80;
var d = new Array(N);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 164 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

var lw = new Array(WMAX - WMIN + 1);


var i,j,t;
// tworzymy zbiór wejściowy do sortowania
for(i = 0; i < N; i++)
d[i] = WMIN + Math.floor(Math.random() * (WMAX - WMIN + 1));
// wyświetlamy zawartość zbioru przed sortowaniem
t = "Przed sortowaniem:<BR><BR>";
for(i = 0; i < N; i++)
if((i + 1) % 20) t += d[i] + " "; else t += d[i] + "<BR>";
t += "<BR>";
// sortujemy
// najpierw zerujemy liczniki
for(i = WMIN; i <= WMAX; i++) lw[i - WMIN] = 0;
// zliczamy w odpowiednich licznikach wystąpienia
// wartości elementów sortowanego zbioru
for(i = 0; i < N; i++) lw[d[i] - WMIN]++;
// zapisujemy do zbioru wynikowego numery niezerowych liczników
// tyle razy, ile wynosi ich zawartość
j = 0;
for(i = WMIN; i <= WMAX; i++) while(lw[i - WMIN]--) d[j++] = i;
// wyświetlamy zawartość zbioru po sortowaniu
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++)
if((i + 1) % 20) t += d[i] + " "; else t += d[i] + "<BR>";
// koniec
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Kubełkowe
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Zobacz również na:


Sortowanie rozrzutowe | Listy | Sortowanie kubełkowe 2 | Sortowanie przez zliczanie | Sortowanie pozycyjne

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 165 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0020.php 166 / 209


Algorytmy Sortujące - Listy 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Listy
Lists
Podrozdziały Tematy pokrewne
Budowa Listy Programy Sortowanie rozrzutowe
Dodawanie elementu do listy Program w języku Pascal Sortowanie kubełkowe 1
Usuwanie elementu z listy Program w języku C++ Sortowanie kubełkowe 2
Rodzaje list Program w języku Basic Sortowanie przez zliczanie
Program w języku JavaScript Sortowanie pozycyjne

Budowa listy
Pełny algorytm sortowania rozrzutowego wymaga nowej struktury danych zwanej listą. Lista zbudowana jest z ciągu elementów:

Dostęp do elementów listy nie jest swobodny. Zwykle z i-tego elementu możemy przejść do elementu następnego (i + 1) lub do
elementu poprzedniego (i - 1). O takiej strukturze danych mówimy, że jest sekwencyjna.
Każdy element listy oprócz swoich danych zawiera dwa dodatkowe pola.

Pole następnika wskazuje element następny na liście.


Pole poprzednika wskazuje element poprzedni na liście.

Pola te umożliwiają przesuwanie się odpowiednio wprzód i wstecz listy.


Zawartość pół następnika i poprzednika zależy od sposobu realizacji listy w pamięci komputera. Jeśli elementy listy będą tworzone
dynamicznie w pamięci pobieranej od systemu operacyjnego, to wtedy pola te będą zawierały adresy elementu następnego i
poprzedniego. Taki sposób tworzenia list jest w ogólnym przypadku najlepszy, jednakże dla nas posiada on pewną istotną
niedogodność - pobieranie pamięci dla każdego nowego elementu listy wymaga wywołania odpowiednich funkcji systemowych, co
zajmuje drogocenny czas. Dlatego wykorzystamy nieco inny sposób.
Poszczególne elementy listy będziemy tworzyli w tablicy (podobnie jak drzewa i stogi w algorytmie sortowania stogowego). Dzięki
temu nie tracimy czasu na przydzielanie pamięci dla kolejnych elementów listy. W przypadku tablicy pola następnika i
poprzednika wskazują indeksy odpowiednich elementów. Umówmy się, iż pierwszy element tablicy ma indeks o wartości 1.
Wartość 0 nie wskazuje zatem żadnego elementu i możemy wykorzystać ją do zaznaczania końców listy:

Ostatni element listy zawiera wartość zero w polu następnika - nie istnieje element następny.
Pierwszy element listy zawiera wartość zero w polu poprzednika - nie istnieje element poprzedni.

Kolejność elementów na liście nie ma nic wspólnego z ich kolejnością w tablicy i może być zupełnie różna:

Lista oprócz samych elementów zawierających dane budowana jest często z dodatkowym elementem zwanym nagłówkiem.
Nagłówek zawiera jedynie indeks pierwszego elementu listy. Jest to jakby wejście, brama, poprzez którą wchodzimy na listę.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 167 / 209


Algorytmy Sortujące - Listy 2014-10-03

Jeśli nagłówek zawiera wartość zero, to lista nie posiada żadnego elementu. Mówimy wtedy, iż lista jest pusta.

Dodawanie elementu do listy


Naszym zadaniem jest dołączenie do listy kolejnego elementu. Przy wykonywaniu tej operacji mogą wystąpić różne sytuacje,
które postaramy się tutaj dokładnie przedstawić w postaci listy kroków. Umówmy się, iż będziemy stosowali następujące
oznaczenia:

L[ ] - tablica, której elementy są elementami listy. Pierwszy indeks wynosi 1.


x - indeks wstawianego na listę elementu, x Î N
ngl - nagłówek listy, ngl Î N
i - zmienna przechowująca indeksy kolejno przeglądanych elementów listy, i Î N

Każdy element listy ma następujące pola:


nastepnik - zawiera indeks następnego elementu na liście, nastepnik Î C
poprzednik - zawiera indeks poprzedniego elementu na liście, poprzednik Î C
dane - dane o dowolnej strukturze, które przechowuje element listy.

Dodawanie elementu na początek listy


K01: L[x].nastepnik ← ngl
K02: L[x].poprzednik ← 0
K03: Jeśli ngl ≠ 0, to L[ngl].poprzednik ← x
K04: ngl ← x
K05: Zakończ

Dodawanie elementu na koniec listy


K01: L[x].nastepnik ← 0
K02: L[x].poprzednik ← 0
K03: Jeśli ngl = 0, to ngl ≠ x i zakończ
K04: i ← ngl
K05: Dopóki L[i].nastepnik ≠ 0: wykonuj i ← L[i].nastepnik
K06: L[i].nastepnik ← x
K07: L[x].poprzednik ← i
K08: Zakończ

Dodawanie elementu przed i-tym elementem listy


K01: L[x].następnik ← i
K02: L[x].poprzednik ←L[i].poprzednik
K03: L[i].poprzednik ← x
K04: Jeśli L[x].poprzednik ≠ 0, to
L[L[x].poprzednik].nastepnik ← x,
inaczej:
ngl ← x
K05: Zakończ

Dodawanie elementu za i-tym elementem listy


K01: L[x].poprzednik ← i
K02: L[x].następnik ← L[i].nastepnik
K03: L[i].nastepnik ← x
K04: Jeśli L[x].nastepnik ≠ 0, to L[L[x].nastepnik].poprzednik ← x
K05: Zakończ

Usuwanie elementu z listy


Z listy będziemy usuwali element o indeksie i. Fizycznie usunięty element zostanie w tablicy, lecz nie będzie go w łańcuchu
elementów tworzących listę. Operacja usuwania elementu z listy nie jest potrzebna przy sortowaniu elementów za pomocą
algorytmów sortowania rozrzutowego, podajemy ją jednak dla kompletności wykładu.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 168 / 209


Algorytmy Sortujące - Listy 2014-10-03

K01: Jeśli L[i].poprzednik ≠ 0, to


L[L[i].poprzednik].nastepnik ← L[i].nastepnik
inaczej
ngl ← L[i].nastepnik
K02: Jeśli L[i].nastepnik ≠ 0, to L[L[i].nastepnik].poprzednik ← L[i].poprzednik
K03: Zakończ

Rodzaje list
Jeśli element listy posiada zdefiniowane pole następnika i poprzednika, to po liście zbudowanej z takich elementów możemy
poruszać się w obu kierunkach - zarówno w przód jak i wstecz. Lista nosi nazwę dwukierunkowej.

Na liście dwukierunkowej zdefiniowane są wszystkie opisane poprzednio operacje wstawiania i usuwania elementu.
Jeśli elementy listy mają zdefiniowane tylko pole następnika, to po liście można poruszać się tylko w jednym kierunku. Lista nosi
nazwę jednokierunkowej. W wielu sytuacjach taki uproszczony rodzaj listy jest zupełnie wystarczający (patrz - przykłady
programów).

Na liście jednokierunkowej zdefiniowana jest operacja wstawiania elementu na początku listy, na końcu listy oraz po i-tym
elemencie.
Jeśli pole następnika ostatniego elementu listy wskazuje pierwszy element, to lista staje się jednokierunkową listą cykliczną. Po
liście możemy się poruszać w kółko bez końca.

Listę dwukierunkową można zapętlić w obu kierunkach otrzymując dwukierunkową listę cykliczną:

Programy
Prezentowane programy demonstrują przykładowe zastosowania list. Generują one 19 3-literowych wyrazów zbudowanych z liter
A, B i C wybieranych losowo. Następnie tworzą trzy listy wyrazów rozpoczynających się kolejno na literę A, B i C.

Efekt uruchomienia programu


Demonstracja zastosowania list
------------------------------
(C)2005 mgr Jerzy Walaszek
3-literowe teksty losowe:
BCA BCC BCB AAB CAC CBA BBB CBC BCC BBB BCB ABA BBB ABC CAC BCB ACC ACB ACC
Na litere A : ACC ACB ACC ABC ABA AAB
Na litere B : BCB BBB BCB BBB BCC BBB BCB BCC BCA
Na litere C : CAC CBC CBA CAC

Zwróć uwagę, iż program umieszcza na listach teksty w kolejności odwrotnej do ich występowania w ciągu wejściowym. Dzieje się
tak dlatego, iż zastosowaliśmy najprostszy wariant - dołączanie elementu na początek listy. Zatem nowe elementy pojawiają się
na liście przed elementami już na niej umieszczonymi. Jeśli chcesz zachować kolejność elementów na liście taką samą jak w
ciągu wejściowym, to ciąg wejściowy należy przeglądać od końca.

DevPascal

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 169 / 209


Algorytmy Sortujące - Listy 2014-10-03

// Przykład zastosowania list


//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
const MAXN = 19;
// Tutaj definiujemy typ elementów listy
type
TElement = record
nastepnik : cardinal;
dane : string[3];
end;
// Tutaj deklarujemy zmienne
var
L : array[1..MAXN] of TElement;
ngl : array[0..2] of cardinal;
i,j : cardinal;
begin
writeln('Demonstracja zastosowania list');
writeln('------------------------------');
writeln(' (C)2005 mgr Jerzy Walaszek ');
writeln;
writeln('3-literowe teksty losowe:');
writeln;
// Tworzymy losowe ciągi 3-literowe w elementach tablicy L[]
randomize;
for i := 1 to MAXN do L[i].dane := char(65 + random(3)) +
char(65 + random(3)) +
char(65 + random(3));
// Wyświetlamy ciągi
for i := 1 to MAXN do write(L[i].dane:4);
writeln; writeln;
// Zerujemy nagłówki list
for i := 0 to 2 do ngl[i] := 0;
// Tworzymy listy wyrazów na A, B i C
for i := 1 to MAXN do
begin
j := ord(L[i].dane[1]) - 65;
L[i].nastepnik := ngl[j];
ngl[j] := i
end;
// Odczytujemy kolejne listy i wyświetlamy je w oknie konsoli
for i := 0 to 2 do
begin
write('Na litere ' + char(i + 65) + ' :');
j := ngl[i];
while j > 0 do
begin
write(L[j].dane:4); j := L[j].nastepnik
end;
writeln; writeln;
end;
// Gotowe, kończymy program
writeln;
writeln('Koniec, nacisnij klawisz ENTER...');
readln;
end.

Code::Blocks
// Przykład zastosowania list
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
const int MAXN = 19;
int main()

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 170 / 209


Algorytmy Sortujące - Listy 2014-10-03

{
struct
{
unsigned int nastepnik;
char dane[3];
} L[MAXN+1];
unsigned int ngl[3],i,j;
cout << "Demonstracja zastosowania list\n"
"------------------------------\n"
" (C)2005 mgr Jerzy Walaszek \n\n"
"3-literowe teksty losowe:\n\n";
// Tworzymy losowe ciągi 3-literowe w elementach tablicy L[]
srand((unsigned)time(NULL));
for(i = 1; i <= MAXN; i++)
for(j = 0; j < 3; j++)
L[i].dane[j] = 65 + rand() % 3;
// Wyświetlamy ciągi
for(i = 1; i <= MAXN; i++)
cout << " " << L[i].dane[0] << L[i].dane[1] << L[i].dane[2];
cout << endl << endl;
// Zerujemy nagłówki list
for(i = 0; i < 3; i++) ngl[i] = 0;
// Tworzymy listy wyrazów na A, B i C
for(i = 1; i <= MAXN; i++)
{
j = L[i].dane[0] - 65;
L[i].nastepnik = ngl[j];
ngl[j] = i;
}
// Odczytujemy kolejne listy i wyświetlamy je w oknie konsoli
for(i = 0; i < 3; i++)
{
cout << "Na litere " << (char)(i + 65) << " :";
j = ngl[i];
while(j)
{
cout << " " << L[j].dane[0] << L[j].dane[1] << L[j].dane[2];
j = L[j].nastepnik;
}
cout << endl << endl;
}
// Gotowe, kończymy program
cout << endl;
return 0;
}

Free Basic
' Przykład zastosowania list
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Const MAXN = 19
' Tutaj definiujemy typ elementów listy
Type TElement
nastepnik As Uinteger
dane As String * 3
End Type
' Tutaj deklarujemy zmienne
Dim L(MAXN) As TElement
Dim As Uinteger ngl(0 To 2),i,j
Print "Demonstracja zastosowania list"
Print "------------------------------"
Print " (C)2005 mgr Jerzy Walaszek "
Print
Print "3-literowe teksty losowe:"
Print
' Tworzymy losowe ciągi 3-literowe w elementach tablicy L[]
Randomize
For i = 1 To MAXN
L(i).dane = CHR$(65 + Int(Rnd(1) * 3)) + _

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 171 / 209


Algorytmy Sortujące - Listy 2014-10-03

CHR$(65 + Int(Rnd(1) * 3)) + _


CHR$(65 + Int(Rnd(1) * 3))
Next
' Wyświetlamy ciągi
For i = 1 To MAXN: Print " ";L(i).dane;: Next
Print: Print
' Zerujemy nagłówki list
For i = 0 To 2: ngl(i) = 0: Next
' Tworzymy listy wyrazów na A, B i C
For i = 1 To MAXN
j = Asc(MID$(L(i).dane,1,1)) - 65
L(i).nastepnik = ngl(j)
ngl(j) = i
Next
' Odczytujemy kolejne listy i wyświetlamy je w oknie konsoli
For i = 0 To 2
Print "Na litere ";CHR$(i + 65);" :";
j = ngl(i)
While j > 0
Print " ";L(j).dane;
j = L(j).nastepnik
Wend
Print: Print
Next
' Gotowe, kończymy program
Print
Print "Koniec, nacisnij dowolny klawisz..."
Sleep
End

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="frmblistdemo">
<h3 style="text-align: center">Demonstracja zastosowania list</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - I LO w Tarnowie
</p>
<hr>
<p style="TEXT-ALIGN: center">
<input onclick="main()" type="button" value="Start" name="B1">
</p>
<p id="t_out" style="TEXT-ALIGN: center">...</p>
</form>
<script language=javascript>
// Przykład zastosowania list
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var MAXN = 19;
var ngl = new Array();
var L = new Array();
var i,j,t;
for(i = 1; i <= MAXN; i++) L[i] = new Object();
function main()
{
// Tworzymy losowe ciągi 3-literowe w elementach tablicy L[]
for(i = 1; i <= MAXN; i++)
{
L[i].dane = "";
for(j = 0; j < 3; j++)
L[i].dane += String.fromCharCode(65 + Math.floor(Math.random() * 3));
}
// Wyświetlamy ciągi
t = "3-literowe teksty losowe:<BR><BR>";
for(i = 1; i <= MAXN; i++) t += L[i].dane + " ";
t += "<BR><BR>";

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 172 / 209


Algorytmy Sortujące - Listy 2014-10-03

// Zerujemy nagłówki list


for(i = 0; i < 3; i ++) ngl[i] = 0;
// Tworzymy listy wyrazów na A, B i C
for(i = 1; i <= MAXN; i++)
{
j = L[i].dane.charCodeAt(0) - 65;
L[i].nastepnik = ngl[j];
ngl[j] = i;
}
// Odczytujemy kolejne listy i wyświetlamy je w oknie konsoli
for(i = 0; i < 3; i++)
{
t += "Na litere " + String.fromCharCode(i + 65) + " :";
j = ngl[i];
while(j)
{
t += " " + L[j].dane;
j = L[j].nastepnik;
}
t += "<BR><BR>";
}
// Gotowe, kończymy program
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Demonstracja zastosowania list


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Start
...

Zobacz również na:


Sortowanie rozrzutowe | Sortowanie kubełkowe 1 | Sortowanie kubełkowe 2 | Sortowanie przez zliczanie | Sortowanie pozycyjne

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 173 / 209


Algorytmy Sortujące - Listy 2014-10-03

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0021.php 174 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie kubełkowe
Bucket Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów Sortowanie rozrzutowe
Dodawanie elementu do listy Program w języku Pascal sortujących Sortowanie kubełkowe 1
uporządkowanej Program w języku C++ Podsumowanie Listy
Specyfikacja problemu Program w języku Basic Zadania dla ambitnych Sortowanie przez
Lista kroków Program w języku zliczanie
Schemat blokowy JavaScript Sortowanie pozycyjne

Algorytm
Podany w poprzednim rozdziale algorytm sortowania kubełkowego jest bardzo uproszczony i pozwala sortować tylko liczby
całkowite. Teraz opiszemy pełny algorytm sortowania kubełkowego pozbawiony tych ograniczeń. Najpierw kilka założeń i definicji:
Sortujemy zbiór d[ ] liczb rzeczywistych. Niech wmin oznacza dolny kres wartości elementów d[ ], a wmax niech oznacza kres
górny. Wartości te tworzą przedział liczbowy <wmin, wmax>, w który wpadają wszystkie elementy zbioru. Przedział dzielimy na
m segmentów, które nazwiemy kubełkami. W tym celu obliczamy szerokość kubełka:

wmax - wmin
szkb = m

Poszczególne kubełki to:

dla i = 0,1,...,m: <wmin + i • szkb , wmin + (i +1) • szkb>

czyli

K[0] : <wmin , wmin + szkb)


K[1] : <wmin + szk , wmin + 2 • szkb)
...
K[m - 1] : <wmin + (m - 1) • szkb, wmax)
K[m] : <wmax , wmax + szkb)

Ponieważ poszczególne kubełki tworzą przedziały prawostronnie otwarte, potrzebujemy ostatniego kubełka K[m] dla wartości
maksymalnej wmax, którą mogą osiągać elementy w sortowanym zbiorze. Wynika stąd, iż kubełków będzie m + 1
ponumerowanych kolejno od 0 do m.
Liczba d[j] należy do i-tego kubełka, jeśli spełniona jest nierówność:

wmin + i • szkb d[j] < wmin + (i - 1) • szkb

A stąd otrzymujemy wzór na numer kubełka:

i= [ d[j]sz-kbwmin]
Po wyznaczeniu przedziału kubełków, zerujemy kubełki (tzn. tworzymy w nich puste listy elementów). Następnie przeglądamy
kolejno wszystkie elementy zbioru, wyznaczamy dla nich odpowiednie kubełki i wstawiamy te elementy to kubełków. Operację
wstawiania do kubełka wykonujemy tak, aby wewnątrz kubełka elementy tworzyły listę posortowaną. Jeśli kubełków będzie
odpowiednio dużo, to zawierać będą niewiele elementów, zatem operacja tworzenia listy uporządkowanej nie zajmie dużo czasu.
Po wykonaniu przebiegu dystrybucyjnego w poszczególnych kubełkach będziemy posiadali uporządkowane listy elementów.
Wykonujemy przebieg zbierający - przeglądamy poszczególne kubełki pobierając z list przechowywane w nich elementy i
umieszczając je w zbiorze wynikowym. W efekcie otrzymamy zbiór posortowany.

Przykład:

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 175 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

Dla zobrazowania zasady sortowania kubełkowego posortujemy tą metodą poniższy zbiór liczb:

{ 23/4 11/4 4/5 41/2 14/5 1/2 }

Określamy zakres wartości elementów zbioru:

wmin = 1/2
wmax = 41/2

Ustalamy liczbę kubełków m = 4.


Wyliczamy szerokość kubełka:

wmax - wmin 41/2 - 1/2


szkb = = =1
m 4

Wyznaczamy zakresy kolejnych kubełków:

K[0] : <1/2, 11/2)


K[1] : <11/2, 21/2)
K[2] : <21/2, 31/2)
K[3] : <31/2, 41/2)
K[4] : <41/2, 51/2)

Poszczególne elementy zbioru umieszczamy w kubełkach, których numery wyznaczamy ze wzoru:

element - wmin
i= [ szkb ]
23/4 - 1/2
[ 1 ] = [2 / ] = 2
23/4 : i = 1
4
1/ - / 1 1
1 / :i=[ 1 ]=[ / ]=0
1 4 2 3
4 4
/ - /4 1
/ :i=[ 1 ]=[ / ]=0
5 2
4 3
5 10
4/ - / 1 1
4 / :i=[ 1 ] = [4] = 4
1 2 2
2
1/ - / 4 1
1 / :i=[ 1 ] = [1 / ] = 1
4 5 2 3
5 10
/ - /1 1
/ :i=[ 1 ] = [0] = 0
1 2 2
2

Kubełki mają następującą zawartość:

K[0] : <1/2, 11/2) : 1/2, 4/5, 11/4


K[1] :<11/2, 21/2) :14/5
K[2] :<21/2, 31/2) :23/4
K[3] :<31/2, 41/2) :
K[4] :<41/2, 51/2) :41/2

Pobieramy elementy z kolejnych kubełków i umieszczamy je w zbiorze wynikowym. Zbiór jest posortowany.

{ 1/2 4/5 11/4 14/5 23/4 41/2 }

Dodawanie elementu do listy uporządkowanej


Elementy umieszczane w kolejnych kubełkach muszą być posortowane rosnąco. Do sortowania wykorzystamy naturalny w tym
przypadku algorytm sortowania przez wstawianie. Dla listy przyjmuje on następującą postać:

Dane wejściowe
L[ ] - tablica elementów, z których zbudowana jest lista. Każdy element posiada pole następnik oraz pole dane.
K[ ] - tablica nagłówków list. Elementy K[ ] są liczbami całkowitymi.
ine - indeks nowego elementu w tablicy L[ ], który będzie dodany do listy kubełka, ine N

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 176 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

ikb - indeks kubełka w tablicy K[ ], do listy którego dodajemy element, ikb N


we - wartość dodawanego elementu, we R

Dane wyjściowe
Na liście kubełka K[ikb] zostaje umieszczony nowy element o wartości pola dane równej we. Lista jest posortowana
rosnąco
Zmienne pomocnicze
ip - indeks poprzedniego elementu na liście, ip C
ib - indeks bieżącego elementu na liście, ib C

Lista kroków wstawiania elementu na listę z sortowaniem


K01: L[ine].nastepnik ← 0; L[ine].dane ← we Inicjujemy nowy element listy
K02: ip ← 0; ib ← K[ikb] Inicjujemy wskaźniki poprzedniego elementu oraz bieżącego
K03: Dopóki (ib > 0) (L[ib].dane < we) wykonuj Szukamy miejsca wstawienia nowego elementu na liście skojarzonej z
ip ← ib kubełkiem
ib ← L[ib].nastepnik
K04: Jeśli ip = 0, to Jeśli wskaźnik poprzedniego elementu listy jest równy 0, to pętla z kroku 3
L[ine].nastepnik ← ib; nie wykonała ani jednego obiegu. Dzieje się tak w dwóch przypadkach:
K[ikb] ← ine lista kubełka jest pusta
pierwszy element listy przechowuje dane większe od we
idź do K07
W obu przypadkach nowy element należy wstawić na początek listy. Po tej
operacji przechodzimy na koniec algorytmu do kroku 7
K05: Jeśli ib = 0, to Jeśli wskaźnik bieżącego elementu jest równy 0, to nowy element należy
L[ip].nastepnik ← ine wstawić na koniec listy - za elementem wskazywanym przez wskaźnik ip. Po
Idź do K07 tej operacji przechodzimy do kroku 7
K06: L[ip].nastepnik ← ine Jeśli nie wystąpiły dwie poprzednie sytuacje, to pozostaje jedynie wstawienie
L[ine].nastepnik ← ib nowego elementu pomiędzy elementy wskazywane przez ip oraz ib.
K07: ine ← ine + 1 Zwiększamy wskaźnik wolnej pozycji w tablicy elementów list L[ ] i kończymy
Zakończ algorytm.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów do posortowania; n Î N
d[ ] - tablica n-elementowa z elementami rzeczywistymi do posortowania. Indeks pierwszego elementu wynosi 1.
wmin - najmniejszy element w tablicy d[ ]; wmin Î R
wmax - największy element w tablicy d[ ]; wmax Î R

Dane wyjściowe
d[ ] - tablica z posortowanymi rosnąco elementami
Zmienne pomocnicze
L[ ] - n-elementowa tablica elementów list. Każdy element posiada całkowite pole następnik oraz rzeczywiste pole
dane. Indeksy elementów rozpoczynają się od wartości 1.
K[ ] - tablica (n + 1) elementowa zawierająca nagłówki list kubełków. Każdy element jest liczbą całkowitą. Indeksy
elementów rozpoczynają się od wartości 0.
szkb - szerokość przedziału objętego przez kubełek, szkb Î R
ikb - wyznaczony dla danego elementu numer kubełka, ikb Î C
ine - indeks wolnej pozycji w tablicy L[ ]; ine Î N
i,j - zmienne licznikowe pętli; i,j Î C
we - wartość sortowanego elementu; we Î R

Lista kroków
K01: Dla i = 0,1,...,n: wykonuj K[i] ← 0
w -w
K02: szkb ← max min
n
K03: ine ← 1
K04: Dla i = 1,2,...,n: wykonuj K05...K07
K05: we ← d[i]
w -w
K06: ikb ← [ e min]
szkb
K07: Wstaw wartość we na listę kubełka K[ikb]
K08: j ← 1

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 177 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

K09: Dla ikb = 0,1,...,n: wykonuj K10...K13


K10: i ← K[ikb]
K11: Dopóki i > 0: wykonuj K12...K14
K12: d[j] ← L[i].dane
K13: j ←j + 1
K14: i ← L[i].nastepnik
K15: Zakończ

Schemat blokowy
Pierwszą operacją algorytmu jest wyzerowanie nagłówków list K[ ].
Następnie obliczamy szerokość przedziału kubełka i zapamiętujemy ją
w zmiennej szkb.
Elementy list będziemy tworzyli kolejno w tablicy L[ ]. Ustawiamy
zmienną ine na pierwszy element tej tablicy. Zmienna ta pełni rolę
wskaźnika wolnego elementu w puli L[ ].
Rozpoczynamy pętlę nr 1, której zadaniem jest umieszczenie
wszystkich elementów zbioru d[ ] w listach kubełków K[ ]. Element i-
ty z d[ ] zapamiętujemy w zmiennej roboczej we (aby zmniejszyć ilość
odwołań do tablicy d[ ]). Obliczamy numer kubełka ikb, do którego trafi
pobrany element we. Następnie wartość we wstawiamy na listę K[ikb]
za pomocą procedury wstawiania elementu na listę uporządkowaną.
Pętla nr 1 jest kontynuowana dotąd, aż wszystkie elementy zbioru d[ ]
znajdą się na odpowiednich listach kubełków K[ ]. Operacja
dystrybucji (rozrzucenia) elementów zostaje zakończona.
Druga faza algorytmu ma za zadanie pozbierać elementy z
poszczególnych list uporządkowanych zawartych w kubełkach K[ ].
Zmienna j pełni rolę indeksu wstawianych do d[ ] elementów. Dlatego
przyjmuje wartość 1 - początek tablicy d[ ].
Pętla nr 2 wyznacza kolejne kubełki K[ ].
Pętla wewnętrzna nr 3 przegląda elementy listy danego kubełka i
zapisuje je do zbioru d[ ].
Po zakończeniu pętli nr 2 w zbiorze d[ ] mamy posortowane elementy. Algorytm jest zakończony.

Programy
Efekt uruchomienia programu
Sortowanie Kubelkowe II
------------------------------
(C)2005 mgr Jerzy Walaszek
Przed sortowaniem:
-508.97 417.11 180.18 457.34 355.41 -813.29 -25.21 189.09 -464.17 -649.78
-126.22 811.71 244.45 889.28 77.94 286.25 -92.35 596.31 -4.15 28.44
353.39 -238.40 433.72 589.48 18.92 -198.85 -39.25 809.69 -260.31 -860.96
-487.18 257.20 683.59 -344.36 297.30 -235.84 -8.61 15.26 -939.39 -126.28
Po sortowaniu:
-939.39 -860.96 -813.29 -649.78 -508.97 -487.18 -464.17 -344.36 -260.31 -238.40
-235.84 -198.85 -126.28 -126.22 -92.35 -39.25 -25.21 -8.61 -4.15 15.26
18.92 28.44 77.94 180.18 189.09 244.45 257.20 286.25 297.30 353.39
355.41 417.11 433.72 457.34 589.48 596.31 683.59 809.69 811.71 889.28

DevPascal
// Sortowanie kubełkowe - wersja II
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
const
N = 40;
WMIN = -1000.0;
WMAX = 1000.0;
// Tutaj definiujemy typ elementów listy
type
TElement = record
nastepnik : cardinal;
dane : real;
end;
// Tutaj deklarujemy zmienne

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 178 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

var
d : array[1..N] of real;
L : array[1..N] of TElement;
K : array[0..N] of integer;
we,szkb : real;
ikb,ine,ip,ib,i,j : integer;
begin
writeln(' Sortowanie Kubelkowe II ');
writeln('------------------------------');
writeln(' (C)2005 mgr Jerzy Walaszek ');
writeln;
// Generujemy zawartość tablicy d[] i wyświetlamy ją
randomize;
writeln('Przed sortowaniem:');
writeln;
for i := 1 to N do
begin
d[i] := WMIN + random() * (WMAX - WMIN);
write(d[i]:8:2);
end;
writeln;
// Zerujemy kubełki
for i := 0 to N do K[i] := 0;
// Obliczamy szerokość kubełka
szkb := (WMAX - WMIN) / N;
ine := 1;
// Rozrzucamy poszczególne elementy d[i] na listach K[]
for i := 1 to N do
begin
we := d[i];
ikb := round((we - WMIN) / szkb);
L[ine].nastepnik := 0; L[ine].dane := we;
ip := 0; ib := K[ikb];
while (ib > 0) and (L[ib].dane < we) do
begin
ip := ib; ib := L[ib].nastepnik;
end;
if ip = 0 then
begin
L[ine].nastepnik := ib; K[ikb] := ine
end
else if ib = 0 then
L[ip].nastepnik := ine
else
begin
L[ip].nastepnik := ine; L[ine].nastepnik := ib;
end;
inc(ine);
end;
// wybieramy dane z kubełków i umieszczamy je w d[]
j := 1;
for ikb := 0 to N do
begin
i := K[ikb];
while i > 0 do
begin
d[j] := L[i].dane;
inc(j); i := L[i].nastepnik;
end;
end;
// Koniec. Wyświetlamy wyniki
writeln('Po sortowaniu:');
writeln;
for i := 1 to N do write(d[i]:8:2);
writeln;
writeln('KONIEC. Nacisnij klawisz Enter...');
readln;
end.

Code::Blocks
// Sortowanie kubełkowe - wersja II
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 179 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

using namespace std;


const int N = 40;
const double WMIN = -1000.0;
const double WMAX = 1000.0;
int main()
{
struct
{
unsigned nastepnik;
double dane;
} L[N + 1];
double d[N],we,szkb;
int K[N + 1],ikb,ine,ip,ib,i,j;
cout.precision(2); // 2 cyfry po przecinku
cout.setf(ios::fixed); // format stałoprzecinkowy
cout << " Sortowanie Kubelkowe II \n"
"------------------------------\n"
" (C)2005 mgr Jerzy Walaszek \n\n"
"Przed sortowaniem:\n\n";
// Generujemy zawartość tablicy d[] i wyświetlamy ją
srand((unsigned)time(NULL));
for(i = 0; i < N; i++)
{
d[i] = WMIN + (double)rand() / (double)(RAND_MAX+1) * (WMAX - WMIN);
cout << setw(8) << d[i];
}
cout << endl;
// Zerujemy kubełki
for(i = 0; i <= N; i++) K[i] = 0;
// Obliczamy szerokość kubełka
szkb = (WMAX - WMIN) / N;
ine = 1;
// Rozrzucamy poszczególne elementy d[i] na listach K[]
for(i = 0; i < N; i++)
{
we = d[i];
ikb = (int)((we - WMIN) / szkb);
L[ine].nastepnik = 0; L[ine].dane = we;
ip = 0; ib = K[ikb];
while((ib > 0) && (L[ib].dane < we))
{
ip = ib; ib = L[ib].nastepnik;
}
if(!ip)
{
L[ine].nastepnik = ib; K[ikb] = ine;
}
else if(!ib) L[ip].nastepnik = ine;
else
{
L[ip].nastepnik = ine; L[ine].nastepnik = ib;
}
ine++;
}
// wybieramy dane z kubełków i umieszczamy je w d[]
j = 0;
for(ikb = 0; ikb <= N; ikb++)
{
i = K[ikb];
while(i)
{
d[j++] = L[i].dane; i = L[i].nastepnik;
}
}
// Koniec. Wyświetlamy wyniki
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++) cout << setw(8) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie kubełkowe - wersja II
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 180 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 40
Const WMIN = -1000
Const WMAX = 1000
' Tutaj definiujemy typ elementów listy
Type TElement
nastepnik As Uinteger
dane As Double
End Type
' Tutaj deklarujemy zmienne
Dim As Double d(N),we,szkb
Dim As TElement L(N)
Dim As Integer K(0 To N),ikb,ine,ip,ib,i,j
Print " Sortowanie Kubelkowe II "
Print "------------------------------"
Print " (C)2005 mgr Jerzy Walaszek "
Print
' Generujemy zawartość tablicy d[] i wyświetlamy ją
Randomize
Print "Przed sortowaniem:"
Print
For i = 1 To N
d(i) = WMIN + Rnd(1) * (WMAX - WMIN)
Print Using "#####.##"; d(i);
Next
Print
' Zerujemy kubełki
For i = 0 To N: K(i) = 0: Next
' Obliczamy szerokość kubełka
szkb = (WMAX - WMIN) / N
ine = 1
' Rozrzucamy poszczególne elementy d[i] na listach K[]
For i = 1 To N
we = d(i)
ikb = Int((we - WMIN) / szkb)
L(ine).nastepnik = 0: L(ine).dane = we
ip = 0: ib = K(ikb)
While (ib > 0) And (L(ib).dane < we)
ip = ib: ib = L(ib).nastepnik
Wend
If ip = 0 Then
L(ine).nastepnik = ib: K(ikb) = ine
Elseif ib = 0 Then
L(ip).nastepnik = ine
Else
L(ip).nastepnik = ine: L(ine).nastepnik = ib
End If
ine += 1
Next
' wybieramy dane z kubełków i umieszczamy je w d[]
j = 1
For ikb = 0 To N
i = K(ikb)
While i > 0
d(j) = L(i).dane
j += 1: i = L(i).nastepnik
Wend
Next
' Koniec. Wyświetlamy wyniki
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "#####.##"; d(i);: Next
Print
Print "KONIEC. Nacisnij dowolny klawisz..."
Sleep
End

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;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 181 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

BORDER-BOTTOM: #ff9933 1px outset;


BACKGROUND-COLOR: #ffcc66" name="frmbucketsort">
<h3 style="text-align: center">Sortowanie Kubełkowe II</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 kubełkowe - wersja II
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 40;
var WMIN = -1000;
var WMAX = 1000;
var d = new Array();
var L = new Array();
var K = new Array();
var we,szkb,ikb,ine,ip,ib,i,j,t;
for(i = 1; i <= N; i++) L[i] = new Object();
function main()
{
// Generujemy zawartość tablicy d[] i wyświetlamy ją
t = "Przed sortowaniem:<BR><BR>";
for(i = 0; i < N; i++)
{
d[i] = WMIN + Math.random() * (WMAX - WMIN);
t += d[i].toFixed(2) + "&nbsp; ";
if(!((i + 1) % 10)) t += "<BR>";
}
t += "<BR>";
// Zerujemy kubełki
for(i = 0; i <= N; i++) K[i] = 0;
// Obliczamy szerokość kubełka
szkb = (WMAX - WMIN) / N;
ine = 1;
// Rozrzucamy poszczególne elementy d[i] na listach K[]
for(i = 0; i < N; i++)
{
we = d[i];
ikb = Math.floor((we - WMIN) / szkb);
L[ine].nastepnik = 0; L[ine].dane = we;
ip = 0; ib = K[ikb];
while((ib > 0) && (L[ib].dane < we))
{
ip = ib; ib = L[ib].nastepnik;
}
if(!ip)
{
L[ine].nastepnik = ib; K[ikb] = ine;
}
else if(!ib) L[ip].nastepnik = ine;
else
{
L[ip].nastepnik = ine; L[ine].nastepnik = ib;
}
ine++;
}
// wybieramy dane z kubełków i umieszczamy je w d[]
j = 0;
for(ikb = 0; ikb <= N; ikb++)
{
i = K[ikb];
while(i)
{
d[j++] = L[i].dane; i = L[i].nastepnik;
}
}
// Koniec. Wyświetlamy wyniki
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++)
{

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 182 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

t += d[i].toFixed(2) + "&nbsp; ";


if(!((i + 1) % 10)) t += "<BR>";
}
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Kubełkowe II
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Badanie algorytmów sortowania


W celach badawczych testujemy czas wykonania algorytmu sortowania kubełkowego w środowisku opisanym we wstępie.
Program testujący jest następujący:
DLA
GENIUSZA
DevPascal
// Program testujący czas sortowania dla
// danego algorytmu sortującego
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program TestCzasuSortowania;
uses Windows;
const
NAZWA = 'Sortowanie kubełkowe';
K1 = '-----------------------------------------------------------';
K2 = '(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie';
K3 = '------n---------tpo---------tod---------tpp---------tpk---------tnp';
K4 = '-------------------------------------------------------------------';
MAX_LN = 8; // określa ostatnie LN
LN : array[1..8] of integer = (1000,2000,4000,8000,16000,32000,64000,128000);
var
d : array[1..128000] of real; // sortowana tablica
n : integer; // liczba elementów
wmin,wmax : real; // zakres elementów
qpf,tqpc : int64; // dane dla pomiaru czasu
qpc1,qpc2 : int64;
// Tutaj umieszczamy procedurę sortującą tablicę d
//-------------------------------------------------------
function Sort : extended;
type
TElement = record
nastepnik : cardinal;
dane : real;
end;
var
L : array[1..128000] of TElement;
K : array[0..128000] of integer;
we,szkb : real;
ikb,ine,ip,ib,i,j : integer;
begin
QueryPerformanceCounter(addr(qpc1));
for i := 0 to n do K[i] := 0;
szkb := (wmax - wmin) / n;
ine := 1;
for i := 1 to n do
begin
we := d[i];
ikb := round((we - wmin) / szkb);
L[ine].nastepnik := 0; L[ine].dane := we;
ip := 0; ib := K[ikb];
while (ib > 0) and (L[ib].dane < we) do
begin
ip := ib; ib := L[ib].nastepnik;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 183 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

if ip = 0 then
begin
L[ine].nastepnik := ib; K[ikb] := ine
end
else if ib = 0 then
L[ip].nastepnik := ine
else
begin
L[ip].nastepnik := ine; L[ine].nastepnik := ib;
end;
inc(ine);
end;
j := 1;
for ikb := 0 to n do
begin
i := K[ikb];
while i > 0 do
begin
d[j] := L[i].dane;
inc(j); i := L[i].nastepnik;
end;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
var
i,j,k : integer;
tpo,tod,tpp,tpk,tnp : extended;
f : Text;
begin
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
// Wydruk na ekran
writeln('Nazwa: ',NAZWA);
writeln(K1);
writeln(K2);
writeln;
writeln(K3);
// Wydruk do pliku
writeln(f,'Nazwa: ',NAZWA);
writeln(f,K1);
writeln(f,K2);
writeln(f,'');
writeln(f,K3);
for i := 1 to MAX_LN do
begin
n := LN[i];
// Czas sortowania zbioru posortowanego
wmin := 1; wmax := n;
for j := 1 to n do d[j] := j;
tpo := Sort;
// Czas sortowania zbioru posortowanego odwrotnie
for j := 1 to n do d[j] := n - j;
tod := Sort;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na początku - średnia z 10 obiegów
tpp := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[1] := random * n + 1;
tpp += Sort;
end;
tpp /= 10;
// Czas sortowania zbioru posortowanego
// z przypadkowym elementem na końcu - średnia z 10 obiegów
tpk := 0;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := k;
d[n] := random * n + 1;
tpk += Sort;
end;
tpk /= 10;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 184 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

// Czas sortowania zbioru nieuporządkowanego - średnia z 10 obiegów


tnp := 0; wmin := 0; wmax := 1;
for j := 1 to 10 do
begin
for k := 1 to n do d[k] := random;
tnp += Sort;
end;
tnp /= 10;
writeln(n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
writeln(f,n:7,tpo:12:6,tod:12:6,tpp:12:6,tpk:12:6,tnp:12:6);
end;
writeln(K4);
writeln(f,K4);
writeln(f,'Koniec');
closefile(f);
writeln;
writeln('Koniec. Wyniki w pliku WYNIKI.TXT');
end
else writeln('Na tym komputerze program testowy nie pracuje !');
writeln;
write('Nacisnij klawisz ENTER...'); readln;
end.

Otrzymane wyniki są następujące (dla komputera o innych parametrach wyniki mogą się różnić co do wartości czasów wykonania,
dlatego w celach porównawczych proponuję uruchomić podany program na komputerze czytelnika):

Zawartość pliku wygenerowanego przez program

Nazwa: Sortowanie kubełkowe


-----------------------------------------------------------
(C)2011/2012 I Liceum Ogolnoksztalcace w Tarnowie
------n---------tpo---------tod---------tpp---------tpk---------tnp
1000 0.000144 0.000141 0.000142 0.000142 0.000318
2000 0.000286 0.000286 0.000285 0.000294 0.000922
4000 0.000573 0.000571 0.000577 0.000573 0.002066
8000 0.001121 0.001183 0.001226 0.001230 0.004032
16000 0.002410 0.002389 0.002635 0.002450 0.008189
32000 0,004836 0.004761 0.005129 0.005151 0.017092
64000 0.009612 0.010023 0.010583 0.010323 0.032754
128000 0.019054 0.019218 0.020842 0.021200 0.070825
-------------------------------------------------------------------
Koniec
Objaśnienia oznaczeń (wszystkie czasy podano w sekundach):
n - ilość elementów w sortowanym zbiorze
tpo- czas sortowania zbioru posortowanego
tod- czas sortowania zbioru posortowanego malejąco
tpp- czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp- czas sortowania zbioru z losowym rozkładem elementów
(Arkusz kalkulacyjny Excel do wyznaczania klasy czasowej złożoności obliczeniowej)
(Arkusz kalkulacyjny Excel do wyznaczania wzrostu prędkości sortowania)

Podsumowanie
Analizując wyniki obliczeń w arkuszu kalkulacyjnym otrzymanych czasów sortowania dla algorytmu sortowania kubełkowego
wyciągamy następujące wnioski:

Cechy Algorytmu Sortowania Kubełkowego


klasa złożoności obliczeniowej optymistyczna
klasa złożoności obliczeniowej typowa O(n)
klasa złożoności obliczeniowej pesymistyczna ?
Sortowanie w miejscu NIE
Stabilność NIE

Klasy złożoności obliczeniowej szacujemy następująco:


optymistyczna - dla zbiorów uporządkowanych (z niewielką liczbą elementów nie na swoich miejscach) - na podstawie
czasów tpo, tpp, tpk
typowa - dla zbiorów o losowym rozkładzie elementów - na podstawie czasu tnp
pesymistyczna - dla zbiorów posortowanych odwrotnie - na podstawie czasu tod. W przypadku tego algorytmu sortowania
nie jest to przypadek pesymistyczny.

Własności algorytmu
Algorytm tpo tod tpp tpk tnp
O(n) O(n) O(n) O(n) O(n)

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 185 / 209


Algorytmy Sortujące - Sortowanie kubełkowe 2014-10-03

Sortowanie kubełkowe
tpo ≈ tod tpp ≈ tpk tnp ≈ 10tod
3
1. Analiza wyników obliczeń w arkuszu kalkulacyjnym pozwala stwierdzić, iż wszystkie czasy sortowania są proporcjonalne
do liczby elementów. Zatem algorytm ten posiada liniową klasę złożoności obliczeniowej O(n).
2. Czas sortowania zbioru nieuporządkowanego jest wyraźnie dłuższy od czasów sortowania zbiorów uporządkowanych.
3. Algorytm jest mało czuły na niewielkie zaburzenia w zbiorach uporządkowanych.

Wzrost prędkości sortowania


Algorytmy tpo tod tpp tpk tnp
log n log n log n log n log n
2
Sortowanie przez scalanie ≈ ≈ 2 ≈ 2 ≈ 2 ≈ 2
Sortowanie szybkie 16 15 16 16 21
dobrze dobrze dobrze dobrze dobrze

4. Algorytm sortowania kubełkowego wykazuje logarytmiczny wzrost prędkości sortowania w stosunku do


algorytmu sortowania szybkiego wraz ze wzrostem liczby elementów w sortowanym zbiorze. Musimy jednak
sprawiedliwie przyznać, iż w przypadku ogólnym algorytm sortowania szybkiego był szybszy dla
maksymalnej, badanej przez nas liczby elementów równej 128000. Z prostej symulacji wynika, iż algorytm
sortowania kubełkowego stanie się szybszy dopiero dla około 4 milionów elementów. Zatem raczej nie
stanowi on zagrożenia dla Quick Sort.

Zadania dla ambitnych


1. Dlaczego zbiory nieuporządkowane są sortowane przez algorytm sortowania kubełkowego dużo wolniej od zbiorów częściowo
uporządkowanych?
2. Uzasadnij, iż algorytm sortowania kubełkowego w podanej postaci nie jest stabilny.
3. Jak przywrócić stabilność w algorytmie sortowania kubełkowego?

Zobacz również na:


Sortowanie rozrzutowe | Sortowanie kubełkowe 1 | Listy | Sortowanie przez zliczanie | Sortowanie pozycyjne

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany


Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0022.php 186 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie przez zliczanie


Counting Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Sortowanie rozrzutowe
Specyfikacja problemu Program w języku Pascal Sortowanie kubełkowe 1
Lista kroków Program w języku C++ Listy
Schemat blokowy Program w języku Basic Sortowanie kubełkowe 2
Program w języku JavaScript Sortowanie pozycyjne

Algorytm
Zasadę pracy algorytmu sortowania przez zliczanie jest najlepiej przedstawić za pomocą przykładu.

Przykład:
Posortować rosnąco zbiór danych:
{6361490182649375927324187085836253}
Czynności wstępne
Dla każdej wartości w zbiorze przygotowujemy licznik i ustawiamy go na 0.
[0:0] [1:0] [2:0] [3:0] [4:0] [5:0] [6:0] [7:0] [8:0] [9:0]
Obieg zliczający
Przeglądamy kolejne elementy zbioru i zliczamy ich wystąpienia w odpowiednich licznikach. Np. element 6 powoduje
zwiększenie o 1 licznika nr 6. Po wykonaniu tego obiegu w poszczególnych licznikach mamy ilość wystąpień każdej
wartości. W naszym przykładzie otrzymamy:
[0:2] [1:3] [2:4] [3:5] [4:3] [5:3] [6:4] [7:3] [8:4] [9:3]
Teraz poczynając od drugiego licznika sumujemy zawartość licznika oraz jego poprzednika i otrzymujemy:
[0:2] [1:5] [2:9] [3:14] [4:17] [5:20] [6:24] [7:27] [8:31] [9:34]
W wyniku tej operacji w każdym liczniku otrzymaliśmy ilość wartości mniejszych lub równych numerowi licznika,
które występują w zbiorze wejściowym. Na przykład:
[0:2] - w zbiorze wejściowym są dwie wartości 0
[1:5] - w zbiorze wejściowym jest pięć wartości mniejszych lub równych 1
[2:9] - w zbiorze wejściowym jest dziewięć wartość mniejszych lub równych 2, itd.
Zwróć uwagę, iż stan licznika określa teraz ostatnią pozycję w zbiorze uporządkowanym, na której należy umieścić
wartość równą numerowi licznika:

Wartość: 0 0 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 8 8 8 8 9 9 9
Pozycja: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

Obieg dystrybucyjny
Przeglądamy jeszcze raz zbiór wejściowy idąc od ostatniego elementu do pierwszego (aby zachować stabilność
sortowania). Każdy element umieszczamy w zbiorze wynikowym na pozycji równej zawartości licznika dla tego
elementu. Po wykonaniu tej operacji licznik zmniejszamy o 1. Dzięki temu następna taka wartość trafi na
wcześniejszą pozycję.
W naszym przykładzie rozpoczynamy od ostatniej liczby 3. Jej licznik ma zawartość [3:14]. Zatem liczbę 3
umieszczamy w zbiorze wynikowym na pozycji 14 i zmniejszamy o 1 stan licznika otrzymując [3:13]. Kolejna liczba
3 trafi teraz na pozycję 13, itd.
Dla liczby 5 stan licznika wynosi [5:20]. Umieszczamy ją zatem na 20 pozycji i licznik zmniejszamy o 1 otrzymując
[5:19].
Postępujemy w ten sam sposób z pozostałymi elementami zbioru. W efekcie zbiór wynikowy będzie posortowany
rosnąco:

{0011122223333344455566667778888999}

Podsumowanie

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 187 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

Przyjrzawszy się dokładnie algorytmowi sortowania przez zliczanie możesz zastanawiać się, dlaczego postępujemy
w tak dziwny sposób? Przecież mając zliczone wystąpienia każdej wartości w licznikach, możemy je od razu
przepisać do zbioru wyjściowego, jak zrobiliśmy w pierwszej wersji algorytmu sortowania kubełkowego. Miałbyś
rację, gdyby chodziło jedynie o posortowanie liczb. Jest jednak inaczej.
Celem nie jest posortowanie jedynie samych wartości elementów. Sortowane wartości są zwykle tzw. kluczami, czyli
wartościami skojarzonymi z elementami, które wyliczono na podstawie pewnego kryterium Sortując klucze chcemy
posortować zawierające je elementy. Dlatego do zbioru wynikowego musimy przepisać całe elementy ze zbioru
wejściowego, gdyż w praktyce klucze stanowią jedynie część (raczej małą) danych zawartych w elementach. Zatem
algorytm sortowania przez zliczanie wyznacza docelowe pozycje elementów na podstawie reprezentujących je
kluczy, które mogą się wielokrotnie powtarzać. Następnie elementy są umieszczane na właściwym miejscu w
zbiorze wyjściowym. Prześledź dokładnie podany poniżej algorytm oraz przykładowe programy, a wszystko powinno
się wyjaśnić.

Specyfikacja problemu
Dane wejściowe
d[ ] - zbiór elementów do posortowania. Każdy element posiada pole klucz, wg którego dokonuje się sortowania.
Pole klucz jest liczbą całkowitą. Indeksy elementów rozpoczynają się od 1.
n - ilość elementów w zbiorze d[ ]. n N
k min - minimalna wartość klucza, k min C
k max - maksymalna wartość klucza, k max C

Dane wyjściowe
b[ ] - zbiór z posortowanymi elementami ze zbioru d[ ]. Indeksy elementów rozpoczynają się od 1.
Zmienne pomocnicze
i - zmienna dla pętli iteracyjnych, i C
L[ ] - tablica liczników wartości kluczy. Elementy są liczbami całkowitymi. Indeksy przebiegają kolejne wartości od
k min do k max.

Lista kroków
K01: Dla i = k min, k min + 1,...,k max: wykonuj L[i] ← 0
K02: Dla i = 1,2,...,n: wykonuj L[d[i].klucz] ← L[d[i].klucz] + 1
K03: Dla i = k min + 1, k min + 2,...,k max: wykonuj L[i] ← L[i] + L[i - 1]
K04: Dla i = n, n - 1,...,1: wykonuj K05...K06
K05: b[ L[ d[i].klucz ] ] ← d[i]
K06: L[ d[i].klucz ] ← L[ d[i].klucz ] - 1
K07: Zakończ

Schemat blokowy
Algorytm sortowania przez zliczanie zbudowany jest z kolejno
następujących po sobie pętli iteracyjnych.
W pętli nr 1 przygotowujemy liczniki wystąpień poszczególnych
kluczy. Ustawiamy je na 0.
W pętli nr 2 przeglądamy kolejne elementy zbioru zwiększając o 1
licznik o numerze równym wartości klucza w sortowanym elemencie
zbioru. Po zakończeniu tej pętli w licznikach mamy ilość wystąpień
poszczególnych kluczy.
W pętli numer 3 przekształcamy zliczone wartości wystąpień kluczy
n a ostatnie pozycje elementów z danym kluczem w zbiorze
wyjściowym.
W pętli nr 4 ponownie przeglądamy zbiór wejściowy (idąc od końca do
początku, aby zachować kolejność elementów równych - inaczej
algorytm nie byłby stabilny) i przesyłamy elementy ze zbioru
wejściowego do zbioru wyjściowego na pozycję o numerze zawartym
w liczniku skojarzonym z kluczem elementu. Po przesłaniu licznik
zmniejszamy o 1, aby kolejny element o tej samej wartości klucza
trafił na poprzednią pozycję (idziemy wstecz, zatem kolejność
elementów o tym samym kluczu zostanie zachowana). Po
zakończeniu tej pętli dane w zbiorze wynikowym są posortowane
rosnąco. Kończymy zatem algorytm.
Zwróć uwagę, iż algorytm sortowania przez zliczanie nie porównuje ze sobą żadnych elementów zbioru. Teoretycznie
udowodniono, iż algorytmy sortujące, które porównują ze sobą elementy zbioru nie mogą osiągać w przypadku ogólnym lepszej
klasy złożoności obliczeniowej O(n log n). Ten algorytm nie porównuje elementów, zatem łamie tę granicę.

Aby wyznaczyć klasę złożoności obliczeniowej algorytmu sortowania przez zliczanie, przyjrzyjmy się mu bliżej.

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 188 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

Pętla nr 1 wykonuje m = kmax - kmin + 1 operacji zerowania liczników. Jej czas wykonania jest proporcjonalny do m (ilość
możliwych wartości kluczy), zatem ma klasę O(m).
Pętla nr 2 przegląda n elementów zbioru i dla każdego elementu wykonuje operację zwiększania licznika wg numeru klucza.
Klasa złożoności wynosi O(n).
Pętla nr 3 wykonuje m - 1 dodawań - klasa złożoności O(m).
Pętla nr 4 przepisuje elementy ze zbioru wejściowego do wyjściowego i zmniejsza o 1 wartości liczników. Ilość wykonanych
operacji wynosi n, zatem jest to klasa złożoności O(n).
Z tego porównania widzimy jasno, iż na czas wykonania algorytmu ma wpływ zarówno m (ilość wartości kluczy) jak i n (ilość
sortowanych elementów). Stąd klasa złożoności obliczeniowej wynosi O(m + n).

Programy
Prezentowane programy generują pseudolosowe ciągi 3-literowych wyrazów zbudowanych z liter A, B oraz C. Dla każdego
wygenerowanego wyrazu jest wyliczany klucz określający jego alfabetyczną kolejność:
Wyraz AAA AAB AAC ABA ABB ... CCA CCB CCC
Klucz 0 1 2 3 4 ... 24 25 26
Wyrazy są rosnąco sortowane wg wartości klucza.

Efekt uruchomienia programu


Sortowanie Przez Zliczanie
------------------------------
(C)2005 mgr Jerzy Walaszek
Przed sortowaniem:
CAC CAA AAB BAB AAC CAB CBC BCC ACC AAA ACA BCC ABC CAC ACC CAA ACB BCC CAB CAA
ACA CCB BAC BCA ABB ABB CAB CAC AAA BCA BCC ACB AAA BAA CAC AAB BCA CCB CAB CAA
BCB BBB BBB BCB BCB CAA BAA CCC BAA BCC AAC CBC BAA BCA BAA CAC ABA ABC CAA CCC
CBA ABC BCA BBA ACC BBB CBC ACA ABC ACC BBA CCC BBA CAB BBC BBB ABB AAC CCB BCA
Po sortowaniu:
AAA AAA AAA AAB AAB AAC AAC AAC ABA ABB ABB ABB ABC ABC ABC ABC ACA ACA ACA ACB
ACB ACC ACC ACC ACC BAA BAA BAA BAA BAA BAB BAC BBA BBA BBA BBB BBB BBB BBB BBC
BCA BCA BCA BCA BCA BCA BCB BCB BCB BCC BCC BCC BCC BCC CAA CAA CAA CAA CAA CAA
CAB CAB CAB CAB CAB CAC CAC CAC CAC CAC CBA CBC CBC CBC CCB CCB CCB CCC CCC CCC

DevPascal
// Sortowanie przez zliczanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
const
N = 80;
KMIN = 0;
KMAX = 26;
// Tutaj definiujemy typ elementu
type
TElement = record
klucz : cardinal;
wyraz : string[3];
end;
// Zmienne
var
d,b : array[1..N] of TElement;
L : array[KMIN..KMAX] of cardinal;
i,j,v : integer;
s : string;
begin
writeln(' Sortowanie Przez Zliczanie ');
writeln('------------------------------');
writeln(' (C)2005 mgr Jerzy Walaszek ');
writeln;
writeln('Przed sortowaniem:');
writeln;
// Generujemy losowe elementy do sortowania oraz ich klucze
randomize;
for i := 1 to N do
begin
s := '';
for j := 1 to 3 do s := s + char(65 + random(3));
d[i].wyraz := s;
d[i].klucz := 0;
v := 1;
for j := 3 downto 1 do
begin
inc(d[i].klucz, v * (ord(d[i].wyraz[j]) - 65));

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 189 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

v := 3 * v;
end;
end;
// Wyświetlamy wygenerowane elementy
for i := 1 to N do write(d[i].wyraz:4);
writeln;
// Zerujemy liczniki
for i := KMIN to KMAX do L[i] := 0;
// Zliczamy wystąpienia kluczy
for i := 1 to N do inc(L[d[i].klucz]);
// Obliczamy pozycje końcowe elementów
for i := KMIN + 1 to KMAX do inc(L[i], L[i - 1]);
// Przepisujemy elementy z d[ ] do b[ ]
for i := N downto 1 do
begin
b[L[d[i].klucz]] := d[i];
dec(L[d[i].klucz]);
end;
// Wyświetlamy wyniki w b[ ]
writeln('Po sortowaniu:');
writeln;
for i := 1 to N do write(b[i].wyraz:4);
writeln;
writeln('Koniec. Nacisnij klawisz Enter...');
readln;
end.

Code::Blocks
// Sortowanie przez zliczanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int N = 80;
const int KMIN = 0;
const int KMAX = 26;
struct
{
unsigned klucz;
char wyraz[3];
} d[N],b[N];
unsigned L[KMAX - KMIN + 1];
int i,j,v;
cout << " Sortowanie Przez Zliczanie\n"
"------------------------------\n"
" (C)2005 mgr Jerzy Walaszek\n\n"
"Przed sortowaniem:\n\n";
// Generujemy losowe elementy do sortowania oraz ich klucze
srand((unsigned)time(NULL));
for(i = 0; i < N; i++)
{
for(j = 0; j < 3; j++) d[i].wyraz[j] = 65 + rand() % 3;
d[i].klucz = 0;
v = 1;
for(j = 2; j >= 0; j--)
{
d[i].klucz += v * (d[i].wyraz[j] - 65);
v *= 3;
}
}
// Wyświetlamy wygenerowane elementy
for(i = 0; i < N; i++)
cout << ' ' << d[i].wyraz[0] << d[i].wyraz[1] << d[i].wyraz[2];
cout << endl;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 190 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

// Zerujemy liczniki
for(i = KMIN; i <= KMAX; i++) L[i - KMIN] = 0;
// Zliczamy wystąpienia kluczy
for(i = 0; i < N; i++) L[d[i].klucz - KMIN]++;
// Obliczamy pozycje końcowe elementów
for(i = KMIN + 1; i <= KMAX; i++) L[i - KMIN] += L[i - KMIN - 1];
// Przepisujemy elementy z d[ ] do b[ ]
for(i = N - 1; i >= 0; i--) b[(L[d[i].klucz - KMIN]--) - 1] = d[i];
// Wyświetlamy wyniki w b[ ]
cout << "Po sortowaniu:\n\n";
for(i = 0; i < N; i++)
cout << ' ' << b[i].wyraz[0] << b[i].wyraz[1] << b[i].wyraz[2];
cout << endl;
return 0;
}

Free Basic
' Sortowanie przez zliczanie
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 80
Const KMIN = 0
Const KMAX = 26
' Tutaj definiujemy typ elementu
Type TElement
klucz As Uinteger
wyraz As String * 3
End Type
' Zmienne
Dim As TElement d(N),b(N)
Dim As Uinteger L(KMIN To KMAX)
Dim As Integer i,j,v
Dim s As String
Print " Sortowanie Przez Zliczanie "
Print "------------------------------"
Print " (C)2005 mgr Jerzy Walaszek "
Print
Print "Przed sortowaniem:"
Print
' Generujemy losowe elementy do sortowania oraz ich klucze
Randomize
For i = 1 To N
s = ""
For j = 1 To 3: s += CHR$(65 + Int(Rnd(1) * 3)): Next
d(i).wyraz = s
d(i).klucz = 0
v = 1
For j = 3 To 1 Step -1
d(i).klucz += v * (Asc(MID$(d(i).wyraz,j,1)) - 65)
v *= 3
Next
Next
' Wyświetlamy wygenerowane elementy
For i = 1 To N: Print " "; d(i).wyraz;: Next
Print
' Zerujemy liczniki
For i = KMIN To KMAX: L(i) = 0: Next
' Zliczamy wystąpienia kluczy
For i = 1 To N: L(d(i).klucz) += 1: Next
' Obliczamy pozycje końcowe elementów
For i = KMIN + 1 To KMAX: L(i) += L(i - 1): Next
' Przepisujemy elementy z d[ ] do b[ ]
For i = N To 1 Step -1

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 191 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

b(L(d(i).klucz)) = d(i)
L(d(i).klucz) -= 1
Next
' Wyświetlamy wyniki w b[ ]
Print "Po sortowaniu:"
Print
For i = 1 To N: Print " ";b(i).wyraz;: Next
Print
Print "Koniec. Nacisnij dowolny klawisz..."
Sleep
End

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="frmcountingsort">
<h3 style="text-align: center">Sortowanie Przez Zliczanie</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 przez zliczanie
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 80;
var KMIN = 0;
var KMAX = 26;
var d = new Array();
var b = new Array();
var L = new Array;
var i;
for(i = 0; i < N; i++)
{
d[i] = new Object();
b[i] = new Object();
}
function main()
{
var i,j,t,v;
// Generujemy losowe elementy do sortowania oraz ich klucze
for(i = 0; i < N; i++)
{
d[i].wyraz = String.fromCharCode(65 + Math.floor(Math.random() * 3)) +
String.fromCharCode(65 + Math.floor(Math.random() * 3)) +
String.fromCharCode(65 + Math.floor(Math.random() * 3));
d[i].klucz = 0;
v = 1;
for(j = 2; j >= 0; j--)
{
d[i].klucz += v * (d[i].wyraz.charCodeAt(j) - 65);
v *= 3;
}
}
// Wyświetlamy wygenerowane elementy
t = "Przed sortowaniem:<BR><BR>";
for(i = 0; i < N; i++) t += " " + d[i].wyraz;
t += "<BR><BR>";
// Zerujemy liczniki
for(i = KMIN; i <= KMAX; i++) L[i - KMIN] = 0;
// Zliczamy wystąpienia kluczy
for(i = 0; i < N; i++) L[d[i].klucz - KMIN]++;
// Obliczamy pozycje końcowe elementów

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 192 / 209


Algorytmy Sortujące - Sortowanie przez zliczanie 2014-10-03

for(i = KMIN + 1; i <= KMAX; i++) L[i - KMIN] += L[i - KMIN - 1];
// Przepisujemy elementy z d[ ] do b[ ]
for(i = N - 1; i >= 0; i--) b[(L[d[i].klucz - KMIN]--) - 1] = d[i];
// Wyświetlamy wyniki w b[ ]
t += "Po sortowaniu:<BR><BR>";
for(i = 0; i < N; i++) t += " " + b[i].wyraz;
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Przez Zliczanie


(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj
...

Zobacz również na:


Sortowanie rozrzutowe | Sortowanie kubełkowe 1 | Listy | Sortowanie kubełkowe 2 | Sortowanie pozycyjne

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)

Temat:
Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php 193 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Sortowanie Pozycyjne
Radix Sort
Podrozdziały Tematy pokrewne
Algorytm Programy Badanie algorytmów sortujących Sortowanie rozrzutowe
Specyfikacja problemu Program w języku Pascal Podsumowanie Sortowanie kubełkowe 1
Lista kroków Program w języku C++ Zadania dla ambitnych Listy
Schemat blokowy Program w języku Basic Sortowanie kubełkowe 2
Program w języku JavaScript Sortowanie przez zliczanie

Algorytm
Pozycją (ang. radix) nazywamy miejsce cyfry w zapisie liczby. Sortowanie pozycyjne polega na sortowaniu elementów wg
kolejnych (licząc od końca) cyfr liczby. Algorytm sortujący musi być stabilny, tzn. nie może zmieniać kolejności elementów
równych, w przeciwnym razie efekty poprzednich sortowań zostaną utracone.

Przykład:
Posortować algorytmem sortowania pozycyjnego zbiór liczb:
{ 547 398 247 153 121 792 421 }
Liczby posortujemy wg kolejnych od końca cyfr:

start ??x ?x? x?? koniec


547 121 121 121 121
398 421 421 153 153
247 792 547 247 247
153 153 247 398 398
121 547 153 421 421
792 247 792 547 547
421 398 398 792 792

Po posortowaniu ostatniej cyfry liczby tworzą ciąg posortowany.


Sortowanie wg poszczególnych cyfr możemy przeprowadzić w czasie liniowym. Operację musimy wykonać tyle
razy, z ilu cyfr zbudowane są liczby reprezentujące sortowane elementy. Jeśli liczby są równomiernie rozłożone w
reprezentowanym zbiorze, to n elementów może mieć do (logpn + 1) cyfr, gdzie p jest podstawą systemu zapisu
liczb. Zatem czas sortowania będzie proporcjonalny do iloczynu n(logpn + 1). Klasa złożoności obliczeniowej jest
równa O(n log n).

Przykład:
Posortować algorytmem sortowania pozycyjnego zbiór liczb binarnych:
{100111 111011 011101 101011 001111 101000 110011 100001 101101 111111 000011}

start koniec
100111 101000 101000 101000 100001 100001 000011 000011
111011 100111 011101 100001 110011 000011 001111 001111
011101 111011 100001 111011 000011 100111 011101 011101
101011 011101 101101 101011 100111 101000 100001 100001
001111 101011 100111 110011 101000 101011 100111 100111
101000 001111 111011 000011 111011 101101 101000 101000
110011 110011 101011 011101 101011 001111 101011 101011
100001 100001 001111 101101 011101 110011 101101 101101
101101 101101 110011 100111 101101 111011 110011 110011
111111 111111 111111 001111 001111 011101 111011 111011
000011 000011 000011 111111 111111 111111 111111 111111

Sortowanie wg bitów jest bardzo proste, jednakże mało efektywne. Lepszym rozwiązaniem jest przyjęcie za podstawę p liczby
będącej potęgą 2, np. 24 lub 28. W takim przypadku sortujemy wg grup bitów (dla 24 - grupy 4 bitów, dla 28 - grupy 8 bitów).

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 194 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

Zgodnie z podanym wcześniej wzorem klasa czasowej złożoności obliczeniowej będzie równa:

dla p = 24 : O(n log16 n)


dla p = 28 : O(n log256 n)

Oba wzory sprowadzają się do O(n log n) (udowodnij to), lecz sortowanie wykonywane jest odpowiednio 4 i 8 razy szybciej
(mniejsze współczynniki proporcjonalności c).
Jako algorytm sortujący idealnie pasuje opisany w poprzednim rozdziale algorytm sortowania przez zliczanie.

Specyfikacja problemu
Dane wejściowe
n - liczba elementów w sortowanym zbiorze, n Î N
d[ ] - sortowany zbiór danych. Indeksy elementów rozpoczynają się od wartości 1.
MAXel - maksymalna wartość sortowanych elementów

Dane wyjściowe
d[ ] - posortowany rosnąco zbiór danych

Zmienne pomocnicze
b[ ] - pomocniczy zbiór danych. Indeksy elementów rozpoczynają się od 1.
m - maska bitowa do wydzielania bitu z elementu, m Î N
i - zmienna sterująca pętli, i Î N
L0 - licznik bitów 0, L0 Î N
L1 - licznik bitów 1, L1 Î N

Lista kroków
Sortuj(z1[ ], z2[ ], m)
K01: L0 ← 0; L1 ← 0
K02: Dla i = 1,2,...,n: wykonuj K03
K03: Jeśli z1[i] m ≠ 0, to
L1 ← L1 + 1
inaczej
L0 ← L0 + 1
K04: L1 ← L1 + L0
K05: Dla i = n, n - 1,...,1: wykonuj K06
K06: Jeśli z1[i] m ≠ 0, to
z2[L1] ← z1[i]; L1 ← L1 - 1
inaczej
z2[L0] ← z1[i]; L0 ← L0 - 1
K07: Zakończ

Główny algorytm sortowania pozycyjnego


K01: m ← 1
K02: Dopóki m ≤ MAXel wykonuj K03...K06
K03: Sortuj(d[ ], b[ ], m)
K04: Przesuń bity maski m o jeden w lewo
K05: Sortuj(b[ ], d[ ], m)
K06: Przesuń bity maski m o jeden w lewo
K07: Zakończ

Schemat blokowy

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 195 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

Zasada pracy algorytmu sortowania pozycyjnego jest bardzo prosta. Ustawiamy maskę bitową m tak, aby bit b0 miał wartość 1.
Następnie w pętli warunkowej wywołujemy procedurę sortowania przez zliczanie przekazując jej jako parametry sortowany zbiór
danych d[ ] oraz zbiór pomocniczy b[ ], w którym znajdzie się wynik sortowania, i maskę m. Przesuwamy bity maski o jeden w
lewo. Jeszcze raz wywołujemy procedurę sortującą (zwróć uwagę na zamienioną kolejność zbiorów - sortowany jest b[ ], a wynik
trafia z powrotem do d[ ]) i przesuwamy bity maski o jeden w lewo.
Procedura sortująca działa wg opisanego w poprzednim rozdziale algorytmu sortowania przez zliczanie:
Zerujemy liczniki bitu 0 oraz bitu 1. W pierwszej pętli zliczamy bity 0 i 1. Następnie obliczamy ostatnie pozycje dla elementów
zawierających odpowiednio bit 0 i bit 1. Przepisujemy elementy ze zbioru wejściowego na odpowiadające im pozycje w zbiorze
wyjściowym.

Programy
Efekt uruchomienia programu
Sortowanie pozycyjne
------------------------
(C)2005 Jerzy Walaszek
Przed sortowaniem:
479 964 207 34 789 26 943 371 364 245 413 774 740 391 98 512 952 109 426 671
340 59 614 712 577 384 730 460 463 515 312 737 635 510 60 214 514 226 178 494
652 468 869 792 852 638 417 22 542 633 507 6 98 905 448 358 569 129 723 323
373 777 147 251 862 341 428 992 402 128 196 528 572 65 690 484 569 733 898 238
Po sortowaniu:
6 22 26 34 59 60 65 98 98 109 128 129 147 178 196 207 214 226 238 245
251 312 323 340 341 358 364 371 373 384 391 402 413 417 426 428 448 460 463 468
479 484 494 507 510 512 514 515 528 542 569 569 572 577 614 633 635 638 652 671
690 712 723 730 733 737 740 774 777 789 792 852 862 869 898 905 943 952 964 992

DevPascal
// Sortowanie Pozycyjne
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
program RadixSort;
const
N = 80; // ilość elementów
MAXEL = 999; // maksymalna wartość elementu
type
TZbior = array[1..N] of cardinal;
// Procedura sortująca
procedure Sortuj(var z1,z2 : TZbior; m : cardinal);
var
L : array[boolean] of cardinal;
i : cardinal;
t : boolean;
begin
L[false] := 0; L[true] := 0;
for i := 1 to N do inc(L[(z1[i] and m) > 0]);
inc(L[true], L[false]);
for i := N downto 1 do
begin
t := (z1[i] and m) > 0;
z2[L[t]] := z1[i];
dec(L[t]);
end;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 196 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

var
d,b : TZbior;
i : integer;
m : cardinal;
begin
writeln(' Sortowanie pozycyjne ');
writeln('------------------------');
writeln(' (C)2005 Jerzy Walaszek ');
writeln;
// Generujemy pseudolosową zawartość zbioru d[ ]
randomize;
for i := 1 to N do d[i] := random(MAXEL + 1);
writeln('Przed sortowaniem:');
writeln;
for i := 1 to N do write(d[i]:4);
// Ustawiamy maskę na najmłodszy bit
m := 1;
// Sortujemy
while m <= MAXEL do
begin
Sortuj(d,b,m); m := m shl 1;
Sortuj(b,d,m); m := m shl 1;
end;
// Wyświetlamy wyniki
writeln;
writeln('Po sortowaniu:');
writeln;
for i := 1 to N do write(d[i]:4);
writeln;
writeln('KONIEC. Nacisnij klawisz Enter...'); readln;
end.

Code::Blocks
// Sortowanie Pozycyjne
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
const int N = 80; // ilość elementów
const int MAXEL = 999; // maksymalna wartość elementu
// Procedura sortująca
void Sortuj(unsigned z1[], unsigned z2[], unsigned m)
{
unsigned L[2],i;
L[0] = L[1] = 0;
for(i = 1; i <= N; i++) L[(z1[i] & m) > 0]++;
L[1] += L[0];
for(i = N; i >= 1; i--) z2[L[(z1[i] & m) > 0]--] = z1[i];
}
int main()
{
unsigned d[N+1],b[N+1],i,m;
cout << " Sortowanie pozycyjne \n"
"------------------------\n"
" (C)2005 Jerzy Walaszek \n\n"
"Przed sortowaniem:\n\n";
// Generujemy pseudolosową zawartość zbioru d[ ]
srand((unsigned)time(NULL));
for(i = 1; i <= N; i++)
{
d[i] = rand() % (MAXEL + 1);
cout << setw(4) << d[i];
}
// Ustawiamy maskę na najmłodszy bit
m = 1;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 197 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

// Sortujemy
while(m <= MAXEL)
{
Sortuj(d,b,m); m <<= 1;
Sortuj(b,d,m); m <<= 1;
}
// Wyświetlamy wyniki
cout << "\nPo sortowaniu:\n\n";
for(i = 1; i <= N; i++) cout << setw(4) << d[i];
cout << endl;
return 0;
}

Free Basic
' Sortowanie Pozycyjne
'--------------------------------------------------------
' (C)2012 I LO w Tarnowie
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'--------------------------------------------------------
Option Explicit
Const N = 80 ' ilość elementów
Const MAXEL = 999 ' maksymalna wartość elementu
' Procedura sortująca
Declare Sub Sortuj(z1() As Uinteger, z2() As Uinteger, Byval m As Uinteger)
Sub Sortuj(z1() As Uinteger, z2() As Uinteger, Byval m As Uinteger)
Dim As Uinteger L0,L1,i
L0 = 0: L1 = 0
For i = 1 To N
If (z1(i) And m) > 0 Then
L1 += 1
Else
L0 += 1
End If
Next
L1 += L0
For i = N To 1 Step -1
If (z1(i) And m) > 0 Then
z2(L1) = z1(i): L1 -= 1
Else
z2(L0) = z1(i): L0 -= 1
End If
Next
End Sub
Dim As Uinteger d(N),b(N),i,m
Print " Sortowanie pozycyjne "
Print "------------------------"
Print " (C)2005 Jerzy Walaszek "
Print
' Generujemy pseudolosową zawartość zbioru d( )
Randomize
For i = 1 To N: d(i) = Int(Rnd(1) * (MAXEL + 1)): Next
Print "Przed sortowaniem:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
' Ustawiamy maskę na najmłodszy bit
m = 1
' Sortujemy
While m <= MAXEL
Sortuj(d(),b(),m): m = m Shl 1
Sortuj(b(),d(),m): m = m Shl 1
Wend
' Wyświetlamy wyniki
Print
Print "Po sortowaniu:"
Print
For i = 1 To N: Print Using "####"; d(i);: Next
Print
Print "KONIEC. Nacisnij dowolny klawisz..."
Sleep
End

JavaScript
<html>
<head>

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 198 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

</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="frmradixsort">
<h3 style="text-align: center">Sortowanie Pozycyjne</h3>
<p style="TEXT-ALIGN: center">
(C)2012 I LO w Tarnowie - 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 Pozycyjne
//--------------------------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------------------------------------
var N = 80; // ilość elementów
var MAXEL = 999; // maksymalna wartość elementu
// Procedura sortująca
function Sortuj(z1,z2,m)
{
var L0,L1,i;
L0 = L1 = 0;
for(i = 1; i <= N; i++) if((z1[i] & m) > 0) L1++; else L0++;
L1 += L0;
for(i = N; i >= 1; i--)
if((z1[i] & m) > 0) z2[L1--] = z1[i]; else z2[L0--] = z1[i];
}
function main()
{
var d = new Array(N + 1);
var b = new Array(N + 1);
var i,m,t;
t = "Przed sortowaniem:<BR><BR>";
// Generujemy pseudolosową zawartość zbioru d[ ]
for(i = 1; i <= N; i++)
{
d[i] = Math.floor(Math.random() *(MAXEL + 1));
t += " " + d[i];
}
// Ustawiamy maskę na najmłodszy bit
m = 1;
// Sortujemy
while(m <= MAXEL)
{
Sortuj(d,b,m); m <<= 1;
Sortuj(b,d,m); m <<= 1;
}
// Wyświetlamy wyniki
t += "<BR><BR>Po sortowaniu:<BR><BR>";
for(i = 1; i <= N; i++) t += " " + d[i];
document.getElementById("t_out").innerHTML = t;
}
</script>
</body>
</html>

Tutaj możesz przetestować działanie prezentowanego skryptu:

Sortowanie Pozycyjne
(C)2012 I LO w Tarnowie - I LO w Tarnowie

Sortuj

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 199 / 209


Algorytmy Sortujące - Sortowanie pozycyjne 2014-10-03

...

Zobacz również na:


Sortowanie rozrzutowe | Sortowanie kubełkowe 1 | Listy | Sortowanie kubełkowe 2 | Sortowanie przez zliczanie

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0024.php 200 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

©2011mgr Jerzy Wałaszek


I LO w Tarnowie

Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych.


Autor artykułu: mgr Jerzy Wałaszek, Wersja 4.1

Podsumowanie
Podrozdziały
Porównanie klas czasowej złożoności obliczeniowej
Własności algorytmów sortujących
Porównanie szybkości sortowania
Wnioski
Literatura

Porównanie klas złożoności


W poniższej tabeli zebraliśmy dane z poszczególnych rozdziałów dotyczące wyznaczonych klas złożoności obliczeniowej,
stabilności oraz wykorzystania pamięci operacyjnej opisywanych algorytmów sortujących:

Klasa złożoności
Lp. Nazwa algorytmu Stabilność Sortowanie Zalecane?
optymistyczna typowa pesymistyczna w miejscu

1. Bogo Sort O(1) O(n×n!) O(∞) NIE TAK NIE!!!


2. Stupid Sort O(n) ... O(n2) O(n3) O(n3) TAK TAK NIE

3. Bubble Sort I O(n2) O(n2) O(n2) TAK TAK NIE

4. Bubble Sort II O(n2) O(n2) O(n2) TAK TAK NIE

5. Bubble Sort III O(n) ... O(n2) O(n2) O(n2) TAK TAK TAK/NIE

6. Bubble Sort IV O(n) O(n2) O(n2) TAK TAK TAK


7. Bidirectional Bubble Sort O(n) O(n2) O(n2) TAK TAK TAK

8. Selection Sort O(n2) O(n2) O(n2) NIE TAK TAK/NIE

9. Insertion Sort O(n) O(n2) O(n2) TAK TAK TAK

10. Binary Insertion Sort O(n log n) O(n2) O(n2) TAK TAK NIE

11. Shell Sort O(n1,14) O(n1,15) O(n1,15) NIE TAK TAK


12. Merge Sort O(nlog n) O(nlog n) O(n×log n) TAK NIE TAK

13. Heap Sort O(nlog n) O(nlog n) O(n×log n) NIE TAK TAK

14. Quick Sort O(nlog n) O(nlog n) O(n2) NIE TAK TAK


15. Bucket Sort I O(m + n) O(m + n) O(m + n) NIE NIE TAK/NIE
16. Bucket Sort II O(n) O(n) O(n) NIE NIE TAK/NIE
17. Counting Sort O(m + n) O(m + n) O(m + n) TAK NIE TAK
18. Radix Sort O(nlog n) O(nlog n) O(nlog n) TAK NIE TAK

Własności algorytmów sortujących


W następnej tabeli zebraliśmy wyznaczone przez nas zależności pomiędzy czasami sortowania zbiorów o wybranym rozkładzie
elementów.
tpo - czas sortowania zbioru posortowanego
tod - czas sortowania zbioru posortowanego malejąco
tpp - czas sortowania zbioru posortowanego z losowym elementem na początku
tpk - czas sortowania zbioru posortowanego z losowym elementem na końcu
tnp - czas sortowania zbioru z losowym rozkładem elementów
Własności algorytmu
Lp. Algorytm tpo tod tpp tpk tnp

1. Stupid Sort tpo << tod tpp ≈ 1tpk tnp ≈2tod


2 3

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 201 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

2. Bubble Sort I tpo ≈1tod tpo=tpp=tpk tnp ≈2tod


5 3

3. Bubble Sort II tpo ≈ 1 tod tpo=tpp=tpk tnp ≈3tod


10 5

4. Bubble Sort III tpo << tod tpp << tpk tnp ≈3tod
5
5. Bubble Sort IV tpo << tod tpp ≈5tpk tnp ≈3tod
3 5

6. Bidirectional Bubble Sort tpo << tod tpp ≈9tpk tnp ≈3tod
8 5
7. Selection Sort tpo ≈ tod ≈ tpp ≈ tpk ≈ tnp

8. Insertion Sort tpo << tod tpp ≈ tpk tnp ≈1tod


2

9. Binary Insertion Sort tpo << tod tpp ≈ tpk tnp ≈1tod
2

10. Shell Sort tpo ≈3tod tpp ≈ tpk tnp ≈ 2tod


5

11. Merge Sort tpo ≈ tod tpp ≈ tpk tnp ≈2tod


3
12. Heap Sort tpo ≈7tod tpp ≈ tpk tnp ≈4tod
6 3
13. Quick Sort tpo ≈ tod tpp ≈ tpk tnp ≈8tod
3

14. Bucket Sort II tpo ≈ tod tpp ≈ tpk tnp ≈10tod


3
Lp. Algorytm tpo tod tpp tpk tnp

Porównanie szybkości sortowania


W celu porównania szybkości działania poszczególnych algorytmów sortujących zmierzymy czasy sortowania tego samego zbioru
10000 liczb całkowitych 64-bitowych. Otrzymane wyniki są jedynie orientacyjne - dla innych danych możemy otrzymać nieco inną
kolejność poszczególnych algorytmów. Dlatego zachęcamy czytelnika do eksperymentów na różnych zbiorach danych
(zbudowanych z różnych obiektów - liczb rzeczywistych, łańcuchów znakowych, itp.).
Pomiarów dokonaliśmy w systemie komputerowym wyposażonym w procesor Intel Celeron 1,7GHz, pamięć 512 MB RAM z
wyłączoną obsługą sieci oraz z zamkniętymi wszelkimi, nieistotnymi dla pracy systemu procesami (jest to bardzo ważne,
ponieważ procesy pracujące w tle wpływają dosyć istotnie na otrzymywane wyniki). Program testowy był następujący:

DevPascal
// Program wyznaczający kolejność algorytmów sortujących
// wg czasu sortowania zbioru 10000 liczb naturalnych
// w warunkach kontrolowanego uruchomienia
//--------------------------------------
// (C)2012 I LO w Tarnowie
// I Liceum Ogólnokształcące
// w Tarnowie
//--------------------------------------
program KolAlgSort;
uses Windows;
const
N = 10000; // Ilość sortowanych elementów
WMIN = 0; // Wartość minimalna elementów
WMAX = 10000; // Wartość maksymalna elementów
type
TElement = record
nastepnik : cardinal;
dane : int64;
end;
TZbior = array[1..N] of int64;
var
b,d,e : array[1..N] of int64;
qpf,tqpc : int64;
qpc1,qpc2 : int64;
// Poszczególne algorytmy sortujące
procedure StupidSort;
var
i : integer;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 202 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

x : int64;
begin
i := 1;
repeat
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
i := 1;
continue;
end;
inc(i);
until i = N;
end;
//----------------------------------------------------
procedure BubbleSort1;
var
i,j : integer;
x : int64;
begin
for j := 1 to N - 1 do
for i := 1 to N - 1 do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
end;
end;
//----------------------------------------------------
procedure BubbleSort2;
var
i,j : integer;
x : int64;
begin
for j := N - 1 downto 1 do
for i := 1 to j do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
end;
end;
//----------------------------------------------------
procedure BubbleSort3;
var
i,j,p : integer;
x : int64;
begin
for j := N - 1 downto 1 do
begin
p := 1;
for i := 1 to j do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
p := 0;
end;
if p = 1 then break;
end;
end;
//----------------------------------------------------
procedure BubbleSort4;
var
i,p,pmin,pmax : integer;
x : int64;
begin
pmin := 1; pmax := N - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
if p = 0 then pmin := i;
p := i;
end;
if pmin > 1 then dec(pmin);
pmax := p - 1;
until p = 0;
end;
//----------------------------------------------------
procedure BidirectionalBubbleSort;
var
i,p,pmin,pmax : integer;
x : int64;
begin
pmin := 1; pmax := N - 1;
repeat
p := 0;
for i := pmin to pmax do
if d[i] > d[i + 1] then

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 203 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
p := i;
end;
if p = 0 then break;
pmax := p - 1;
p := 0;
for i := pmax downto pmin do
if d[i] > d[i + 1] then
begin
x := d[i]; d[i] := d[i + 1]; d[i + 1] := x;
p := i;
end;
pmin := p + 1;
until p = 0;
end;
//----------------------------------------------------
procedure SelectionSort;
var
i,j,pmin : integer;
x : int64;
begin
for j := 1 to N - 1 do
begin
pmin := j;
for i := j + 1 to N do
if d[i] < d[pmin] then pmin := i;
x := d[pmin]; d[pmin] := d[j]; d[j] := x;
end;
end;
//----------------------------------------------------
procedure InsertionSort;
var
i,j : integer;
x : int64;
begin
for j := N - 1 downto 1 do
begin
x := d[j];
i := j + 1;
while (i <= N) and (x > d[i]) do
begin
d[i - 1] := d[i];
inc(i);
end;
d[i - 1] := x;
end;
end;
//----------------------------------------------------
procedure BinaryInsertionSort;
var
i,j,ip,ik : integer;
x : int64;
begin
for j := N - 1 downto 1 do
begin
x := d[j];
ip := j;
ik := N + 1;
while ik - ip > 1 do
begin
i := (ik + ip) div 2;
if x <= d[i] then ik := i else ip := i;
end;
for i := j to ip - 1 do d[i] := d[i + 1];
d[ip] := x;
end;
end;
//----------------------------------------------------
procedure ShellSort;
var
i,j,h : integer;
x : int64;
begin
h := 1;
repeat
h := 3 * h + 1;
until h >= N;
h := (h div 9);
while(h > 0) do
begin
for j := N - h downto 1 do
begin
x := d[j];
i := j + h;
while (i <= N) and (x > d[i]) do
begin
d[i - h] := d[i];
i += h;
end;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 204 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

d[i - h] := x;
end;
h := h div 3;
end;
end;
//----------------------------------------------------
procedure MergeSort(i_p,i_k : integer);
var
i_s,i1,i2,i : integer;
begin
i_s := (i_p + i_k + 1) div 2;
if i_s - i_p > 1 then MergeSort(i_p, i_s - 1);
if i_k - i_s > 0 then MergeSort(i_s, i_k);
i1 := i_p; i2 := i_s;
for i := i_p to i_k do
if (i1 = i_s) or ((i2 <= i_k) and (d[i1] > d[i2])) then
begin
b[i] := d[i2]; inc(i2);
end
else
begin
b[i] := d[i1]; inc(i1);
end;
for i := i_p to i_k do d[i] := b[i];
end;
//----------------------------------------------------
procedure HeapSort;
var
i,j,k,m : integer;
x : int64;
begin
for i := 2 to N do
begin
j := i; k := j div 2;
x := d[i];
while (k > 0) and (d[k] < x) do
begin
d[j] := d[k];
j := k; k := j div 2;
end;
d[j] := x;
end;
for i := N downto 2 do
begin
x := d[1]; d[1] := d[i]; d[i] := x;
j := 1; k := 2;
while k < i do
begin
if (k + 1 < i) and (d[k + 1] > d[k]) then
m := k + 1
else
m := k;
if d[m] <= d[j] then break;
x := d[j]; d[j] := d[m]; d[m] := x;
j := m; k := j + j;
end;
end;
end;
//----------------------------------------------------
procedure QuickSort(lewy, prawy : integer);
var
i,j : integer;
piwot,x : int64;
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 QuickSort(lewy, j - 1);
if j + 1 < prawy then QuickSort(j + 1, prawy);
end;
//----------------------------------------------------
procedure BucketSort1;
var
lw : array[WMIN..WMAX] of integer;
i,j : integer;
begin
for i := WMIN to WMAX do lw[i] := 0;
for i := 1 to N do inc(lw[d[i]]);
j := 1;
for i := WMIN to WMAX do
while lw[i] > 0 do
begin
d[j] := i; inc(j); dec(lw[i]);

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 205 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

end;
end;
//----------------------------------------------------
procedure BucketSort2;
var
L : array[1..N] of TElement;
K : array[WMIN..WMAX] of integer;
we : int64;
ine,ip,ib,i,j : integer;
begin
for i := WMIN to WMAX do K[i] := 0;
ine := 1;
for i := 1 to N do
begin
we := d[i];
L[ine].nastepnik := 0; L[ine].dane := we;
ip := 0; ib := K[we];
while (ib > 0) and (L[ib].dane < we) do
begin
ip := ib; ib := L[ib].nastepnik;
end;
if ip = 0 then
begin
L[ine].nastepnik := ib; K[we] := ine
end
else if ib = 0 then
L[ip].nastepnik := ine
else
begin
L[ip].nastepnik := ine; L[ine].nastepnik := ib;
end;
inc(ine);
end;
j := 1;
for ib := WMIN to WMAX do
begin
i := K[ib];
while i > 0 do
begin
d[j] := L[i].dane;
inc(j); i := L[i].nastepnik;
end;
end;
end;
//----------------------------------------------------
procedure CountingSort;
var
L : array[WMIN..WMAX] of cardinal;
i : integer;
begin
for i := WMIN to WMAX do L[i] := 0;
for i := 1 to N do inc(L[d[i]]);
for i := WMIN + 1 to WMAX do L[i] += L[i - 1];
for i := N downto 1 do
begin
b[L[d[i]]] := d[i]; dec(L[d[i]]);
end;
end;
//----------------------------------------------------
procedure SortujBit(var z1,z2 : TZbior; m : int64);
var
L : array[boolean] of cardinal;
i : cardinal;
t : boolean;
begin
L[false] := 0; L[true] := 0;
for i := 1 to N do inc(L[(z1[i] and m) > 0]);
L[true] += L[false];
for i := N downto 1 do
begin
t := (z1[i] and m) > 0;
z2[L[t]] := z1[i];
dec(L[t]);
end;
end;
procedure RadixSort;
var
m : int64;
begin
m := 1;
while m <= WMAX do
begin
SortujBit(d,b,m); m := m shl 1;
SortujBit(b,d,m); m := m shl 1;
end;
end;
// Funkcja pomiaru czasu sortowania
function Sort(nr : integer) : extended;
begin

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 206 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

QueryPerformanceCounter(addr(qpc1));
case nr of
1 : StupidSort;
2 : BubbleSort1;
3 : BubbleSort2;
4 : BubbleSort3;
5 : BubbleSort4;
6 : BidirectionalBubbleSort;
7 : SelectionSort;
8 : InsertionSort;
9 : BinaryInsertionSort;
10 : ShellSort;
11 : MergeSort(1,N);
12 : HeapSort;
13 : QuickSort(1,N);
14 : BucketSort1;
15 : BucketSort2;
16 : CountingSort;
17 : RadixSort;
end;
QueryPerformanceCounter(addr(qpc2));
Sort := (qpc2 - qpc1 - tqpc) / qpf;
end;
// Program główny
//---------------
const
NazwaAlgorytmu : array[1..17] of string =
('Stupid Sort','Bubble Sort I','Bubble Sort II','Bubble Sort III',
'Bubble Sort IV','Bidirectional Bubble Sort','Selection Sort',
'Insertion Sort','Binary Insertion Sort','Shell Sort','Merge Sort',
'Heap Sort','Quick Sort','Bucket Sort I','Bucket Sort II',
'Counting Sort','Radix Sort');
type
TAlgorytm = record
nazwa : string;
czas : extended;
end;
var
algorytm : array[1..18] of TAlgorytm;
i,j : integer;
f : Text;
begin
writeln('Porownanie czasu sortowania wybranych algorytmow');
writeln('-------------------------------------------------------');
writeln('(C)2005 mgr Jerzy Walaszek I LO w Tarnowie');
writeln;
if QueryPerformanceFrequency(addr(qpf)) then
begin
QueryPerformanceCounter(addr(qpc1));
QueryPerformanceCounter(addr(qpc2));
tqpc := qpc2 - qpc1;
assignfile(f,'wyniki.txt'); rewrite(f);
writeln(f,'Porownanie czasu sortowania wybranych algorytmow');
writeln(f,'-------------------------------------------------------');
writeln(f,'(C)2005 mgr Jerzy Walaszek I LO w Tarnowie');
writeln(f,'');
randomize;
for i := 1 to N do e[i] := random(WMAX + 1);
for i := 1 to 17 do
with algorytm[i] do
begin
d := e;
nazwa := NazwaAlgorytmu[i];
czas := Sort(i);
writeln(czas:11:6,' : ',nazwa);
writeln(f,czas:11:6,' : ',nazwa);
end;
for j := 16 downto 1 do
begin
algorytm[18] := algorytm[j];
i := j + 1;
while (i <= 17) and (algorytm[18].czas > algorytm[i].czas) do
begin
algorytm[i - 1] := algorytm[i];
inc(i);
end;
algorytm[i - 1] := algorytm[18];
end;
writeln;
writeln('Ranking:');
writeln;
writeln(f,'');
writeln(f,'Ranking:');
writeln(f,'');
for i := 1 to 17 do
begin
writeln(i:2,'. ',algorytm[i].czas:11:6,' - ',algorytm[i].nazwa);
writeln(f,i:2,'. ',algorytm[i].czas:11:6,' - ',algorytm[i].nazwa);
end;
CloseFile(f);
end
else
writeln('Na tym komputerze nie mozna wykonac pomiaru!');
writeln;

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 207 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

writeln('Koniec - nacisnij ENTER');


readln;
end.

Efekt uruchomienia programu


Porownanie czasu sortowania wybranych algorytmow
-------------------------------------------------------
(C)2005 mgr Jerzy Walaszek I LO w Tarnowie
595.809227 : Stupid Sort
1.274373 : Bubble Sort I
0.940440 : Bubble Sort II
0.917117 : Bubble Sort III
0.936409 : Bubble Sort IV
0.674173 : Bidirectional Bubble Sort
0.369731 : Selection Sort
0.295610 : Insertion Sort
0.274226 : Binary Insertion Sort
0.004668 : Shell Sort
0.004436 : Merge Sort
0.005149 : Heap Sort
0.002832 : Quick Sort
0.000594 : Bucket Sort I
0.001588 : Bucket Sort II
0.000788 : Counting Sort
0.007603 : Radix Sort
Ranking:
1. 0.000594 - Bucket Sort I
2. 0.000788 - Counting Sort
3. 0.001588 - Bucket Sort II
4. 0.002832 - Quick Sort
5. 0.004436 - Merge Sort
6. 0.004668 - Shell Sort
7. 0.005149 - Heap Sort
8. 0.007603 - Radix Sort
9. 0.274226 - Binary Insertion Sort
10. 0.295610 - Insertion Sort
11. 0.369731 - Selection Sort
12. 0.674173 - Bidirectional Bubble Sort
13. 0.917117 - Bubble Sort III
14. 0.936409 - Bubble Sort IV
15. 0.940440 - Bubble Sort II
16. 1.274373 - Bubble Sort I
17. 595.809227 - Stupid Sort

Konkurs szybkości sortowania wygrywają algorytmy sortowania dystrybucyjnego - jest to dosyć oczywiste, ponieważ mają one
liniową klasę złożoności obliczeniowej. Z algorytmów porównujących klasy liniowo logarytmicznej na pierwszej pozycji wyłania się
algorytm sortowania szybkiego. Z algorytmów klasy kwadratowej pierwsze miejsce zajął algorytm binarnego sortowania przez
wstawianie. Tuż za nim jest algorytm sortowania przez wstawianie. Algorytmy sortowania bąbelkowego zamykają naszą listę.
Algorytm sortowania głupiego jest daleko, daleko w tyle.

Wnioski
Najszybsze algorytmy sortujące to algorytmy sortowania dystrybucyjnego. Jednakże szybkość ich działania jest okupiona dużym
zapotrzebowaniem na pamięć. Algorytmy te mają liniową klasę czasowej złożoności obliczeniowej.
Z algorytmów sortujących w miejscu najszybszym w typowych warunkach jest algorytm sortowania szybkiego. Posiada liniowo
logarytmiczną klasę czasowej złożoności obliczeniowej. Jednakże dla niekorzystnych danych może się degradować do klasy
kwadratowej.
Wolniejszym (około dwa razy) algorytmem sortowania klasy liniowo logarytmicznej jest algorytm sortowania stogowego. Algorytm
ten nie degraduje się do niższej klasy złożoności obliczeniowej i może być alternatywą dla algorytmu sortowania szybkiego.
Bardzo obiecujące wyniki otrzymaliśmy dla algorytmu sortowania metodą Shella.
W klasie kwadratowej złożoności obliczeniowej zalecany jest do stosowania algorytm sortowania przez wstawianie. Jest bardzo
prosty w implementacji i jednocześnie wystarczająco szybki. Dla zbiorów w znacznym stopniu uporządkowanych wykazuje liniową
klasę złożoności obliczeniowej. Dlatego nadaje się np. do sortowania zbioru uporządkowanego, do którego dodajemy nowy
element - zbiór będzie posortowany szybciej niż przez algorytm sortowania szybkiego (porównaj czasy tpp i tpk dla 32000
elementów). Ten wniosek jasno pokazuje, iż nie ma uniwersalnych algorytmów sortujących.
Algorytmów sortowania bąbelkowego raczej należy unikać.

Literatura
Donald Knuth, The Art of Computer Programming, Vol.3: Sorting and Searching, Addison-Wesley, 1998
Robert Segewick, Algorithms, Addison-Wesley, 1984
Jerzy Grębosz, Symfonia C++, Oficyna Kallimach, Kraków 1999
Niklaus Wirth, Algorytmy + struktury danych = programy, WNT Warszawa 1980,

List do administratora Serwisu Edukacyjnego I LO


Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:

Uwaga: ← tutaj wpisz wyraz ilo , inaczej list zostanie zignorowany

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 208 / 209


Algorytmy Sortujące - Podsumowanie 2014-10-03

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048


Wyślij Kasuj

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby
rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień
szeroko opisywanych w podręcznikach.

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji I Liceum Ogólnokształcące


GNU Free Documentation License. im. Kazimierza Brodzińskiego
w Tarnowie
(C)2014 mgr Jerzy Wałaszek

http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0025.php 209 / 209

You might also like