Shell sort (Shellovo řazení, řazení se snižujícím se přírůstkem) je kvadratický řadící algoritmus podobný
insertion sortu. Ačkoliv má asymptotickou složitost , tak je z algoritmů této třídy nejvýkonnější.
Princip
Běžný insertion sort si uchovává seznam již seřazených prvků. V každém svém kroku zařadí do seznamu prvek, který s tímto seznamem přímo sousedí. Opakováním tohoto postupu od triviálního případu (seznam čítající pouze první prvek) algoritmus seřadí pole za iterací.
Shell sort funguje obdobně. Základním rozdílem však je, že Shell sort využívá tzv. snižující se přírůstek. To znamená, že algoritmus neřadí prvky, které jsou přímo vedle sebe, ale prvky, mezi nimiž je určitá mezera (tj. první a pátý, pátý a devátý, druhý a šestý...). V každém kroku je pak mezera mezi prvky zmenšena. V okamžiku, kdy se velikost mezery sníží na 1, dojde k řazení sousedních prvků – algoritmus degeneruje na běžný insertion sort. Výhodou tohoto poněkud komplikovaného přístupu je, že jsou prvky vysokých a nízkých hodnot velmi rychle přemístěny na odpovídající stranu pole. Poslední iterace algoritmu (insertion sort) pak již přesouvá naprosté minimum prvků.
Ideální mezera
Základním problémem je ovšem volba ideální vzdálenosti pro porovnávání jednotlivých prvků. Donald Shell (autor algoritmu) původně navrhoval, aby se začínalo na (n je velikost pole) a vzdálenost se vždy půlila. Tento přístup má ovšem tu nevýhodu, že se prvky na sudých a lichých místech porovnávají až v posledním kroku algoritmu. Dalšími pokusy byly například posloupnosti
(Hibbard) se složitostí
nebo
(Sedgewick) se složitostí
, případně
Fibonacciho posloupnost umocněná na dvojnásobek zlatého řezu.
Nejlepší výsledky ovšem podává posloupnost 1, 4, 10, 23, 57, 132, 301, 701, 1750, dále , jejímž autorem je Marcin Ciura.
Vizualizace
Kód
01.
/**
02.
* Shell sort - Shellovo razeni - razeni se snizujicim se prirustkem (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @return serazene pole
05.
*/
06.
public
static
int
[] shellSort(
int
[] array) {
07.
int
gap = array.length /
2
;
08.
while
(gap >
0
) {
//dokud mame co porovnavat
09.
for
(
int
i =
0
; i < array.length - gap; i++) {
//upraveny insertion sort
10.
int
j = i + gap;
11.
int
tmp = array[j];
12.
while
(j >= gap && tmp > array[j - gap]) {
13.
array[j] = array[j - gap];
14.
j -= gap;
15.
}
16.
array[j] = tmp;
17.
}
18.
if
(gap ==
2
) {
//zmena velikosti mezery
19.
gap =
1
;
20.
}
else
{
21.
gap /=
2.2
;
22.
}
23.
}
24.
return
array;
25.
}
01.
/**
02.
* Shell sort - Shellovo razeni - razeni se snizujicim se prirustkem (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @param size velikost pole
05.
* @return serazene pole
06.
*/
07.
int
* shellSort(
int
* array,
int
size) {
08.
int
gap = size / 2;
09.
while
(gap > 0) {
//dokud mame co porovnavat
10.
for
(
int
i = 0; i < size - gap; i++) {
//upraveny insertion sort
11.
int
j = i + gap;
12.
int
tmp = array[j];
13.
while
(j >= gap && tmp > array[j - gap]) {
14.
array[j] = array[j - gap];
15.
j -= gap;
16.
}
17.
array[j] = tmp;
18.
}
19.
if
(gap == 2) {
//zmena velikosti mezery
20.
gap = 1;
21.
}
else
{
22.
gap /= 2.2;
23.
}
24.
}
25.
return
array;
26.
}
01.
/**
02.
* Shell sort - Shellovo razeni - razeni se snizujicim se prirustkem (od nejvyssiho)
03.
* @param array pole k serazeni
04.
* @return serazene pole
05.
*/
06.
public
static
int
[] ShellSort(
int
[] array)
07.
{
08.
int
gap = array.Length / 2;
09.
while
(gap > 0)
//dokud mame co porovnavat
10.
{
11.
for
(
int
i = 0; i < array.Length - gap; i++)
//upraveny insertion sort
12.
{
13.
int
j = i + gap;
14.
int
tmp = array[j];
15.
while
(j >= gap && tmp > array[j - gap])
16.
{
17.
array[j] = array[j - gap];
18.
j -= gap;
19.
}
20.
array[j] = tmp;
21.
}
22.
if
(gap == 2)
//zmena velikosti mezery
23.
{
24.
gap = 1;
25.
}
26.
else
27.
{
28.
gap = (
int
)(gap / 2.2);
29.
}
30.
}
31.
return
array;
32.
}