Sortowanie przez scalanie to algorytm sortowania oparty na metodzie "dziel i rządź" (divide and conquer). Jego główna idea polega na podziale tablicy na mniejsze fragmenty, sortowaniu ich oddzielnie, a następnie łączeniu (scalaniu) w jedną posortowaną całość.
Podziel problem na mniejsze części
Jeśli tablica zawiera więcej niż jeden element, podziel ją na dwie (prawie równe) części.
Proces ten jest powtarzany rekursywnie, aż każda podtablica będzie miała tylko jeden element (a taka tablica jest już posortowana).
Posortuj każdą z części (rekurencyjnie)
Każda podtablica jest sortowana osobno za pomocą tego samego algorytmu.
Scal posortowane podtablice w jedną całość
Dwie posortowane tablice są łączone w jedną, porównując elementy z obu podtablic i układając je w odpowiedniej kolejności.
Proces ten jest powtarzany aż do momentu, gdy cała tablica będzie posortowana.
Rozważmy tablicę:
[38, 27, 43, 3, 9, 82, 10]
[38, 27, 43, 3] | [9, 82, 10]
Dzielimy ponownie:
[38, 27] | [43, 3] | [9, 82] | [10]
Dzielimy dalej, aż każda część zawiera pojedynczy element:
[38] [27] | [43] [3] | [9] [82] | [10]
Scalamy małe fragmenty w większe, zachowując porządek:
[27, 38] | [3, 43] | [9, 82] | [10]
Scalamy dalej:
[3, 27, 38, 43] | [9, 10, 82]
Ostateczne scalanie daje nam:
[3, 9, 10, 27, 38, 43, 82] (tablica posortowana)
Źródło: Jakub Piskorowski
Źródło: Jakub Piskorowski
W każdym kroku algorytmu sortowania przez scalanie tablica jest sukcesywnie dzielona na dwie mniejsze części, aż do osiągnięcia jednoelementowych podtablic. Następnie poszczególne fragmenty są stopniowo scalane w sposób uporządkowany poprzez porównywanie najmniejszych dostępnych wartości z obu podtablic. Dzięki temu unika się konieczności wielokrotnego przeszukiwania tablicy, co znacząco zwiększa efektywność sortowania.
W funkcji MergeSort poprzez wywołanie rekurencyjne dzielimy tablice na dwie części. Na prawą i lewą stronę.
void MergeSort(int* tab, int l, int r) {
if (r > l) {
int m = (l + r) / 2;
MergeSort(tab, l, m); // Podzielenie tablicy na lewa strone
MergeSort(tab, m + 1, r); // Podzielenie tablicy na prawa strone
Merge(tab, l, m, r);
}
}
Należy napisać funkcję, która, po uprzednim podzieleniu tablicy na mniejsze części, wykona prostą operacje porównania oraz na nowu połączy tablice.
Wejście:
tab
- tablica z losowymi wartościami liczb całowitych
l
- indeks lewej strony tablicy
m
- indeks środka tablicy
r
- indeks prawej strony tablicy
Zmienne pomocnicze:
lSize
- przechowywanie rozmiaru lewej tablicy
rSize
- przechowywanie rozmiaru prawej tablicy
indexL
- przechowująca indes lewej tablicy podczas operacji łączenia tablic
indexR
- przechowująca indes prawej tablicy podczas operacji łączenia tablic
Tablice pomocnicze
tabL
- przechowująca tymczasowo wartości lewej tablicy
tabR
- przechowująca tymczasowo wartości prawej tablicy
Lista kroków:
K1: lSize ← m - l + 1
K2: rSize ← r - m
K3: tabL[lSize] Tablica pomocnicza
K4: tabR[rSize] Tablica pomocnicza
K5 Dla x = 0,1,...,lSize Kopiowanie danych do tablic pomocniczych
wykonuj tabL[] ← tab[l+x]
K6: Dla y = 0,1,..., rSize Kopiowanie danych do tablic pomocniczych
wykonuj tabR[] ← tab[m+1-y]
K7: indexL ← 0
K8: indexR ← 0
K9: currIndex = l
K10: Dopóki indexL < lSize oraz indexR < rSize Łaczenie tablicy prawej (R) oraz lewej (L)
wykonuj kroki od K11 do K12
K11: Jeżeli tabL[indexL] <= tabR[indexR]
to tab[currIndex] ← tabL[indexL++]
inaczej tab[currIndex] ← tabR[indexR++]
K12: currIndex++
K13: Dopóki indexL < lSize Jeśli w tablicy(tabL) zostały jeszcze jaieś elementy to kopiujemy je
to tab[currIndex++] = tabL[indexL++]
K14: Dopóki indexR < rSize Jeśli w tablicy(tabR) zostały jeszcze jaieś elementy to kopiujemy je
to tab[currIndex++] = tabR[indexR++]
K15: delete[] tabL
K16: delete[] tabR
Wynik działania programu:
Wprowadz liczbe elementow do posortowania: 8
Tablica przed posortowaniem:
70 | 36 | 86 | 71 | 22 | 71 | 89 | 77 |
Rozpoczecie sortowania
Tablica po sortowaniu:
22 | 36 | 70 | 71 | 71 | 77 | 86 | 89 |