Shell sort
Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od
verze recenzované 9. července 2020; kontroly vyžadují
23 úprav .
Shell sort je třídicí algoritmus , který je vylepšenou verzí řazení vkládání . Myšlenkou metody Shell je porovnat prvky, které jsou nejen vedle sebe, ale také v určité vzdálenosti od sebe. Jinými slovy, jedná se o vkládání třídění s předběžnými „hrubými“ průchody. Podobné vylepšení bublinkového třídění se nazývá hřebenové třídění .
Popis
Při řazení Shell se hodnoty nejprve porovnávají a třídí mezi sebou, stojí jedna od druhé v určité vzdálenosti ( výběr hodnoty viz níže ). Poté se postup opakuje pro některé menší hodnoty a řazení Shell je dokončeno řazením prvků na (tj. obvyklé řazení vložení ). Efektivita Shell řazení je v určitých případech zajištěna tím, že prvky „rychleji“ zapadají (u jednoduchých metod třídění, např. bubble sort , každá permutace dvou prvků snižuje počet inverzí v seznamu o max. z 1 a při řazení Shell může být toto číslo více).
![d](https://wikimedia.org/api/rest_v1/media/math/render/svg/e85ff03cbe0c7341af6b982e47e9f90d235c66ab)
![d](https://wikimedia.org/api/rest_v1/media/math/render/svg/e85ff03cbe0c7341af6b982e47e9f90d235c66ab)
![d=1](https://wikimedia.org/api/rest_v1/media/math/render/svg/958b426c5ace91d4fb7f5a3becd7b21dba288d50)
Přestože je Shellsort v mnoha případech pomalejší než quicksort , má řadu výhod:
- není potřeba zásobníková paměť;
- žádná degradace u špatných datových sad – Quicksort se snadno degraduje na O(n²), což je horší než nejhorší zaručený čas pro Shellsort.
Historie
Shell sort byl pojmenován po svém vynálezci Donaldu Shellovi , který algoritmus publikoval v roce 1959 .
Příklad
Nechť je dán seznam a setřídí se metodou Shell a .
![A=(32,95,16,82,24,66,35,19,75,54,40,43,93,68)](https://wikimedia.org/api/rest_v1/media/math/render/svg/21f738b70c210ca2567d01cf170625c3b0058ac1)
![d](https://wikimedia.org/api/rest_v1/media/math/render/svg/e85ff03cbe0c7341af6b982e47e9f90d235c66ab)
![5,3,1](https://wikimedia.org/api/rest_v1/media/math/render/svg/b43045fc1fc3376530e47ac78299d9bff79bda63)
První krok seřadí podseznamy složené ze všech prvků , které se liší o 5 pozic, tedy podseznamy , , , , .![A](https://wikimedia.org/api/rest_v1/media/math/render/svg/7daff47fa58cdfd29dc333def748ff5fa4c923e3)
![A](https://wikimedia.org/api/rest_v1/media/math/render/svg/7daff47fa58cdfd29dc333def748ff5fa4c923e3)
![A_{{5,1}}=(32,66,40)](https://wikimedia.org/api/rest_v1/media/math/render/svg/e6f77b34a7ea6e899f3a9aad2bcd1eac3c0a8eea)
![A_{{5,2}}=(95,35,43)](https://wikimedia.org/api/rest_v1/media/math/render/svg/6fead81394f44526f703f5fb9ef6d283608da26a)
![A_{{5,3}}=(16,19,93)](https://wikimedia.org/api/rest_v1/media/math/render/svg/f3b457308eace5f6f1c86ed36a2f872e4c97c99d)
![A_{{5,4}}=(82,75,68)](https://wikimedia.org/api/rest_v1/media/math/render/svg/c01703c582c4d7335615acae9a0f2827a0722f8c)
Ve výsledném seznamu jsou ve druhém kroku podseznamy opět setříděny z prvků s odstupem 3 pozic.
Proces končí obvyklým způsobem vložení výsledného seznamu.
Výběr délky mezer
Průměrná doba běhu algoritmu závisí na délce intervalů - , které budou obsahovat seřazené prvky původního pole s kapacitou v každém kroku algoritmu. Existuje několik přístupů k výběru těchto hodnot:
![d](https://wikimedia.org/api/rest_v1/media/math/render/svg/e85ff03cbe0c7341af6b982e47e9f90d235c66ab)
![N](https://wikimedia.org/api/rest_v1/media/math/render/svg/f5e3890c981ae85503089652feb48b191b57aae3)
- sekvence délek mezer původně používaná Shellem: v nejhorším případě bude složitost algoritmu ;
![{\displaystyle d_{1}=N/2,d_{i}=d_{i-1}/2,d_{k}=1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/6787e44fb46b003c6ad48146b2a7cb601fbb4612)
![O(N^{2})](https://wikimedia.org/api/rest_v1/media/math/render/svg/e5d43a3df904fa4d7220f5b86285298aa36d969b)
- Hibbardova navrhovaná sekvence: všechny hodnoty ; takový sled kroků vede k algoritmu složitosti ;
![{\displaystyle 2^{i}-1\leq N,i\in \mathbb {N} }](https://wikimedia.org/api/rest_v1/media/math/render/svg/1d0ae414fdd98fca4eb79b02aba42f8a390516c8)
![O(N^{{3/}})](https://wikimedia.org/api/rest_v1/media/math/render/svg/0ff8d577486acc6b703329c55525ac87909501bf)
- sekvence navržená Sedgwickem : je-li i sudé a je- li i liché. Při použití takových přírůstků je průměrná složitost algoritmu: a v nejhorším případě řádově . Při použití Sedgwickova vzorce byste se měli zastavit na hodnotě inc[s-1], pokud 3*inc[s] > size. [2] ;
![{\displaystyle d_{i}=9\cdot 2^{i}-9\cdot 2^{i/2}+1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/a1fe63653ace9a018f135f818bb963a2e23dc256)
![{\displaystyle d_{i}=8\cdot 2^{i}-6\cdot 2^{(i+1)/2}+1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/b455e9cb3e3b6a39e7a44b6121faf0d9b3e1ce14)
![O(n^{{7/6}})](https://wikimedia.org/api/rest_v1/media/math/render/svg/d38fdcc1b94c0810992aeb5f393fc9823de3b1bb)
![O(n^{{4/}})](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0395f81d3c0239090b4f92eb4a7165626ae0af6)
- sekvence navržená Prattem: všechny hodnoty ; v tomto případě je složitost algoritmu ;
![{\displaystyle 2^{i}\cdot 3^{j}\leq N/2,i,j\in \mathbb {N} }](https://wikimedia.org/api/rest_v1/media/math/render/svg/79a785152eb92340d25530453b84c9dea878e65a)
![O(N(logN)^{2})](https://wikimedia.org/api/rest_v1/media/math/render/svg/ee3e458584d2200531ea0e202d9f75f75fc6abcc)
- empirická sekvence Marcina Ciura (sekvence A102549 v OEIS ): ; je jedním z nejlepších pro třídění pole až do přibližně 4000 prvků. [3] ;
![{\displaystyle d\in \left\{1,4,10,23,57,132,301,701,1750\right\))](https://wikimedia.org/api/rest_v1/media/math/render/svg/7a8ba75f5e7e516b36ae619aad63fbb217581105)
- empirická posloupnost založená na Fibonacciho číslech : ;
![{\displaystyle d\in \left\{F_{n}\right\}}](https://wikimedia.org/api/rest_v1/media/math/render/svg/97668832f7d61fe23be6ee2dd11667319754dfea)
- všechny hodnoty
, ; takový sled kroků vede k algoritmu složitosti .![j\in {\mathbb N}](https://wikimedia.org/api/rest_v1/media/math/render/svg/b54b0f8d5a5eb196ce103460f69c9eb3ec9393fb)
![O(N^{{3/}})](https://wikimedia.org/api/rest_v1/media/math/render/svg/0ff8d577486acc6b703329c55525ac87909501bf)
Implementace v C++
template < typename RandomAccessIterator , typename Compare >
void shell_sort ( RandomAccessIterator první , RandomAccessIterator poslední , Porovnat komp )
{
pro ( auto d = ( poslední - první ) / 2 ; d != 0 ; d / = 2 )
//potřebuji smyčku pro první = a[0..d-1]
for ( auto i = první + d ; i != poslední ; ++ i )
for ( auto j = i ; j - první >= d && comp ( * j , * ( j - d ) ); j -= d )
std :: swap ( * j , * ( j - d ) );
}
Implementace v C
void shell_sort ( int * pole , int velikost ) {
for ( int s = velikost / 2 ; s > 0 ; s / = 2 ) {
for ( int i = s ; i < velikost ; ++ i ) {
for ( int j = i - s ; j >= 0 && pole [ j ] > pole [ j + s ]; j -= s ) {
inttemp = pole [ j ] ;
pole [ j ] = pole [ j + s ];
pole [ j + s ] = temp ;
}
}
}
}
Implementace v Javě
public class ShellSort {
public static void ShellSort ( int [] pole ) {
int h = 1 ;
while ( h <= pole . délka / 3 ) {
h = h * 3 + 1 ;
}
while ( h > 0 ) {
for ( int vnější = h ; vnější < pole . délka ; vnější ++ ) {
int tmp = pole [ vnější ] ;
int vnitřní = vnější ;
while ( vnitřní > h - 1 && pole [ vnitřní - h ] > tmp ) {
pole [ vnitřní ] = pole [ vnitřní - h ] ;
vnitřní -= h ;
}
pole [ vnitřní ] = tmp ;
}
h = ( h - 1 ) / 3 ;
}
}
}
Implementace v Pythonu
def shell_sort ( data : seznam [ int ]) -> seznam [ int ]:
poslední_index = len ( data )
krok = len ( data ) // 2
zatímco krok > 0 :
pro i v rozsahu ( krok , poslední_index , 1 ):
j = i
delta = j - krok
, zatímco delta >= 0 a data [ delta ] > data [ j ]:
data [ delta ], data [ j ] = data [ j ], data [ delta ]
j = delta
delta = j - krok
krok //= 2
návrat dat
Poznámky
- ↑ Shell D. L. A vysokorychlostní třídicí postup // Commun . ACM - [New York] : Association for Computing Machinery , 1959. - Sv. 2, Iss. 7. - S. 30-32. — ISSN 0001-0782 ; 1557-7317 – doi:10.1145/368370.368387
- ↑ J. Incerpi, R. Sedgewick , "Improved Upper Bounds for Shellsort", J. Computer and System Sciences 31, 2, 1985.
- ↑ Marcin Ciura Nejlepší přírůstky za průměrný případ Shellsortu . Získáno 15. září 2009. Archivováno z originálu 30. srpna 2011. (neurčitý)
Odkazy