Mergesort je stabilní řadicí algoritmus typu rozděl
a panuj s asymptotickou
složitostí . Merge sort pracuje na bázi slévání již
seřazených částí pole za pomoci dodatečného pole velikosti
.
Merge sort byl vynalezen v roce 1945 Johnem von Neumannem.
Princip
Slévání
Předpokládejme, že máme dva seznamy (A, B) seřazené v sestupném pořadí. Tyto seznamy můžeme setřídit do jediného seznamu (C) následující procedurou.
V každém kroku vždy porovnejme první prvky obou seznamů (tj. nejvyšší prvky obou seznamů) a vyberme ten vyšší. Tento nakopírujme na konec seznamu C a odstraňme jej ze seznamu původního. Tento postup opakujme tak dlouho, dokud se jeden ze seznamů nevyprázdní. Potom překopírujme zbytek druhého seznamu do C (a odstraňme překopírované prvky z původního seznamu).
Ve skutečnosti slévá merge sort vždy dvě sousední části pole. Drží si dva ukazatele, každý na první prvek seznamu a po každém porovnání přesune jeden z prvků do pomocného pole a posune příslušný ukazatel o jedno místo (címž se dostane na nový nejvyšší prvek příslušného seznamu). Poté, co zkopíruje všechny prvky obou seznamů do pomocného pole, tak celé původní pole přepíše seřazeným seznamem (pomocným polem).
Dělení
Dosud jsme nezmínili, jak algoritmus získá dvě seřazená sousední pole. Dělicí část merge sortu má na svém vstupu celé pole. Pokud je pole sudé délky, tak jej rozdělí na dvě stejně velké části. Má-li pole lichou délku, tak bude jedna část obsahovat o prvek více než druhá. V každém případě pak algoritmus nově vzniklé části dále rekurzivně dělí. V okamžiku, kdy rekurze narazí na seznamy jednotkové velikosti, tak se zastaví. Nyní má algorimus v každé větvi k dispozici dva sousední seznamy, které obsahují jeden prvek a jsou tedy triviálně seřazeny.
Řazení
Merge sort se tedy začne navracet z rekurze a při každém návratu sleje dva seznamy pomocí výše zmíněné procedury slévání. Algoritmus má jistotu, že buď slévá triviálně seřazené prvky nebo seznamy, které již byly slity. V okamžiku, kdy se merge sort plně navrátí z rekurze, tak terminuje. Pole je seřazeno od nevyšší hodnoty.
Kód
01.
/**
02.
* Razeni slevanim (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @param aux pomocne pole stejne delky jako array
05.
* @param left prvni index na ktery se smi sahnout
06.
* @param right posledni index, na ktery se smi sahnout
07.
*/
08.
public
static
void
mergeSort(
int
[] array,
int
[] aux,
int
left,
int
right) {
09.
if
(left == right)
return
;
10.
int
middleIndex = (left + right)/
2
;
11.
mergeSort(array, aux, left, middleIndex);
12.
mergeSort(array, aux, middleIndex +
1
, right);
13.
merge(array, aux, left, right);
14.
15.
for
(
int
i = left; i <= right; i++) {
16.
array[i] = aux[i];
17.
}
18.
}
19.
20.
/**
21.
* Slevani pro Merge sort
22.
* @param array pole k serazeni
23.
* @param aux pomocne pole (stejne velikosti jako razene)
24.
* @param left prvni index, na ktery smim sahnout
25.
* @param right posledni index, na ktery smim sahnout
26.
*/
27.
private
static
void
merge(
int
[] array,
int
[] aux,
int
left,
int
right) {
28.
int
middleIndex = (left + right)/
2
;
29.
int
leftIndex = left;
30.
int
rightIndex = middleIndex +
1
;
31.
int
auxIndex = left;
32.
while
(leftIndex <= middleIndex && rightIndex <= right) {
33.
if
(array[leftIndex] >= array[rightIndex]) {
34.
aux[auxIndex] = array[leftIndex++];
35.
}
else
{
36.
aux[auxIndex] = array[rightIndex++];
37.
}
38.
auxIndex++;
39.
}
40.
while
(leftIndex <= middleIndex) {
41.
aux[auxIndex] = array[leftIndex++];
42.
auxIndex++;
43.
}
44.
while
(rightIndex <= right) {
45.
aux[auxIndex] = array[rightIndex++];
46.
auxIndex++;
47.
}
48.
}
01.
/**
02.
* Razeni slevanim (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @param aux pomocne pole stejne delky jako array
05.
* @param left prvni index na ktery se smi sahnout
06.
* @param right posledni index, na ktery se smi sahnout
07.
*/
08.
void
mergeSort(
int
array[],
int
aux[],
int
left,
int
right) {
09.
if
(left == right)
return
;
10.
int
middleIndex = (left + right)/2;
11.
mergeSort(array, aux, left, middleIndex);
12.
mergeSort(array, aux, middleIndex + 1, right);
13.
merge(array, aux, left, right);
14.
15.
for
(
int
i = left; i <= right; i++) {
16.
array[i] = aux[i];
17.
}
18.
}
19.
20.
/**
21.
* Slevani pro Merge sort
22.
* @param array pole k serazeni
23.
* @param aux pomocne pole (stejne velikosti jako razene)
24.
* @param left prvni index, na ktery smim sahnout
25.
* @param right posledni index, na ktery smim sahnout
26.
*/
27.
void
merge(
int
array[],
int
aux[],
int
left,
int
right) {
28.
int
middleIndex = (left + right)/2;
29.
int
leftIndex = left;
30.
int
rightIndex = middleIndex + 1;
31.
int
auxIndex = left;
32.
while
(leftIndex <= middleIndex && rightIndex <= right) {
33.
if
(array[leftIndex] >= array[rightIndex]) {
34.
aux[auxIndex] = array[leftIndex++];
35.
}
else
{
36.
aux[auxIndex] = array[rightIndex++];
37.
}
38.
auxIndex++;
39.
}
40.
while
(leftIndex <= middleIndex) {
41.
aux[auxIndex] = array[leftIndex++];
42.
auxIndex++;
43.
}
44.
while
(rightIndex <= right) {
45.
aux[auxIndex] = array[rightIndex++];
46.
auxIndex++;
47.
}
48.
}
01.
/**
02.
* Razeni slevanim (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @param aux pomocne pole stejne delky jako array
05.
* @param left prvni index na ktery se smi sahnout
06.
* @param right posledni index, na ktery se smi sahnout
07.
*/
08.
public
static
void
MergeSort(
int
[] array,
int
[] aux,
int
left,
int
right)
09.
{
10.
if
(left == right)
return
;
11.
int
middleIndex = (left + right) / 2;
12.
MergeSort(array, aux, left, middleIndex);
13.
MergeSort(array, aux, middleIndex + 1, right);
14.
Merge(array, aux, left, right);
15.
16.
for
(
int
i = left; i <= right; i++)
17.
{
18.
array[i] = aux[i];
19.
}
20.
}
21.
22.
/**
23.
* Slevani pro Merge sort
24.
* @param array pole k serazeni
25.
* @param aux pomocne pole (stejne velikosti jako razene)
26.
* @param left prvni index, na ktery smim sahnout
27.
* @param right posledni index, na ktery smim sahnout
28.
*/
29.
private
static
void
Merge(
int
[] array,
int
[] aux,
int
left,
int
right)
30.
{
31.
int
middleIndex = (left + right) / 2;
32.
int
leftIndex = left;
33.
int
rightIndex = middleIndex + 1;
34.
int
auxIndex = left;
35.
while
(leftIndex <= middleIndex && rightIndex <= right)
36.
{
37.
if
(array[leftIndex] >= array[rightIndex])
38.
{
39.
aux[auxIndex] = array[leftIndex++];
40.
}
41.
else
42.
{
43.
aux[auxIndex] = array[rightIndex++];
44.
}
45.
auxIndex++;
46.
}
47.
while
(leftIndex <= middleIndex)
48.
{
49.
aux[auxIndex] = array[leftIndex++];
50.
auxIndex++;
51.
}
52.
while
(rightIndex <= right)
53.
{
54.
aux[auxIndex] = array[rightIndex++];
55.
auxIndex++;
56.
}
57.
}