Sortowanie przez scalanie (mergesort)
Sortowanie przez scalanie wstęp W informatyce sortowanie przez scalanie (ang. merge sort), to rekurencyjny algorytm sortowania danych. Algorytm ten jest dobrym przykładem algorytmów typu Dziel i zwyciężaj. Ideą działania tego typu algorytmów jest podział problemu na mniejsze części, których rozwiązanie jest już łatwiejsze.
Sortowanie przez scalanie zasada działania Algorytm mergesort dzieli się na trzy części: dzielenie tablicy na dwa wycinki, wywołanie rekurencyjne algorytmu sortującego na tych wycinkach, scalenie dwóch posortowanych wycinków. Dzielenie tablicy odbywa się dopóki wycinek zawiera więcej niż jeden element. W rezultacie otrzymamy n-wycinków jednoelementowych (gdzie n oznacza ilość elementów w tablicy) Zwróćmy uwagę, iż zbiór jednoelementowy jest z założenia posortowany.
Sortowanie przez scalanie opis słowny algorytmu (procedura mergesort) Podziel tablicę na dwa wycinki Jeżeli lewy wycinek zawiera więcej niż jeden element to wywołaj rekurencyjnie procedurę mergesort Jeżeli prawy wycinek zawiera więcej niż jeden element, to wywołaj rekurencyjnie procedurę mergesort Scal dwa posortowane wycinki
Sortowanie przez scalanie zasada działania Początek algorytmu 4 6 3 2 1 5 8 7 Po pierwszym wywołaniu 4 6 3 2 1 5 8 7 Po drugim wywołaniu 4 6 3 2 1 5 8 7 Po trzecim wywołaniu 4 6 3 2 1 5 8 7
Sortowanie przez scalanie tekst procedury mergesort procedure mergesort(poczatek,koniec: integer; var tab:tablica); var srodek: integer; {deklaracja zmiennej} begin srodek:=(poczatek + koniec) div 2; {wyznaczanie środkowego indeksu} if poczatek < srodek then mergesort(poczatek, srodek); {jeśli lewy wycinek zawiera więcej niż 2 elementy, sortuj lewy wycinek} if srodek+1 < koniec then mergesort(srodek+1, koniec); {jeśli prawy wycinek zawiera więcej niż 2 elementy, sortuj prawy wycinek} merge(poczatek, srodek, koniec; var tab:tablica); {scal dwa posortowane wycinki} end;
Sortowanie przez scalanie scalanie posortowanych tablic (procedura merge) W procedurze scalania dwóch posortowanych wycinków wykorzystamy dwa indeksy: poz1 oraz poz2. Indeks poz1 przebiega pierwszy wycinek, a indeks poz2 przebiega drugi wycinek. Wartości tych indeksów powinny być następujące: poz1:= początek; poz2:=środek+1;
Sortowanie przez scalanie opis słowny algorytmu scalania (merge) Dla każdego elementu dwóch wycinków wykonuj: jeżeli tab[poz1] < tab[poz2] to dodaj do tablicy pomocniczej element tab[poz1] oraz zwiększ indeks poz1 w przeciwnym wypadku dodaj do tablicy pomocniczej element tab[poz2] oraz zwiększ indeks poz2 Rozwiązanie nie uwzględnia sytuacji, gdy któryś z elementów jest pusty.
Sortowanie przez scalanie opis słowny algorytmu scalania (merge) Dla każdego elementu dwóch wycinków wykonuj: jeżeli pierwszy wycinek jest pusty to dodaj do tablicy pomocniczej element tab[poz2] zwiększ poz2 w przeciwnym wypadku jeżeli drugi wycinek jest pusty to dodaj do tablicy pomocniczej element tab[poz1] zwiększ poz1 jeżeli tab[poz1] < tab[poz2] to dodaj do tablicy pomocniczej element tab[poz1] zwiększ indeks poz1 dodaj do tablicy pomocniczej element tab[poz2] zwiększ indeks poz2 koniec
Sortowanie przez scalanie opis słowny algorytmu scalania (merge) Zdanie „wycinek pierwszy jest pusty” realizujemy przy pomocy warunku poz1>środek natomiast zdanie „wycinek drugi jest pusty” realizujemy przy pomocy warunku poz2>koniec
2 3 4 6 1 5 7 8 Sortowanie przez scalanie scalanie elementów poz1 poz2 Początek:=1 Środek:=4 Koniec:=8 2 3 4 6 1 5 7 8 tablica pomocnicza
Sortowanie przez scalanie tekst procedury merge (deklaracje zmiennych i przypisanie zmiennym początkowych wartości) procedure merge(poczatek, srodek, koniec: integer; var tab:tablica); var poz1, poz2, pozx, i : integer; tabx: tablica; begin poz1:=poczatek; poz2:=srodek+1; pozx:=poczatek;
Sortowanie przez scalanie tekst procedury merge (dla każdego elementu z dwóch wycinków wykonuj: jeśli pierwszy wycinek jest pusty przepisz element z wycinka drugiego i zwiększ indeks poz2 o jeden) for i:=poczatek to koniec do begin if poz1 > srodek then tabx[pozx]:=tab[poz2]; poz2:=poz2+1; pozx:=pozx+1; end else
Sortowanie przez scalanie tekst procedury merge (jeśli drugi wycinek jest pusty przepisz element z wycinka pierwszego i zwiększ indeks poz1 o jeden) if poz2 > koniec then begin tabx[pozx]:=tab[poz1]; poz1:=poz1+1; pozx:=pozx+1; end
Sortowanie przez scalanie tekst procedury merge (porównaj wartości elementów tablicy i przepisz mniejszy do tablicy tymczasowej, zwiększ indeks o jeden) else if tab[poz1] < tab[poz2] then begin tabx[pozx]:=tab[poz1]; poz1:=poz1+1; pozx:=pozx+1; end else tabx[pozx]:=tab[poz2]; poz2:=poz2+1; end;
Sortowanie przez scalanie tekst procedury merge (przepisywanie elementów z tablicy pomocniczej do wejściowej) for i:=poczatek to koniec do tab[i]:=tabx[i]; end;
Sortowanie przez scalanie złożoność czasowa algorytmu (nieformalna) Bez straty ogólności załóżmy, że długość ciągu, który mamy posortować jest potęgą 2 (2n). Podczas wykonywania rekurencji otrzymujemy drzewo o głębokości log2n, na każdym poziomie dokonujemy scalenia o łącznym koszcie nc, gdzie c jest stałą zależną od komputera. A więc nieformalnie możemy dowieść, że złożoność algorytmu mergesort to n log2n
Sortowanie przez scalanie przykładowe wyniki działania programu
Sortowanie przez scalanie Literatura A. Strusińska-Walczak, K. Walczak „Programowanie w języku Turbo Pascal 7.0”, Wydawnictwo W&W, 1998 http://www.wikipedia.pl