Shellsort - Shellsort
![]() Shellsort s mezerami 23, 10, 4, 1 v akci
| |
| Třída | Algoritmus řazení |
|---|---|
| Datová struktura | Pole |
| Nejhorší výkon | O ( n 2 ) (nejhorší známá nejhorší mezerová sekvence) O ( n log 2 n ) (nejznámější nejhorší případová mezerová sekvence) |
| Nejlepší výkon | O ( n log n ) (většina sekvencí mezer) O ( n log 2 n ) (nejznámější sekvence mezer v nejhorším případě) |
| Průměrný výkon | závisí na mezerové sekvenci |
| Nejhorší prostorová složitost | О ( n ) celkem, O (1) pomocný |
Shellsort , také známý jako Shell sort nebo Shellova metoda , je srovnání na místě . Může být vnímáno buď jako zobecnění řazení podle výměny ( bublinkové řazení ), nebo řazení podle vložení ( vkládací řazení ). Metoda začíná tříděním párů prvků daleko od sebe, poté postupným zmenšováním mezery mezi porovnávanými prvky. Začínáme-li s prvky daleko od sebe, může přesunout některé nemístné prvky do polohy rychleji než jednoduchá výměna nejbližších sousedů. Donald Shell publikoval první verzi tohoto druhu v roce 1959. Doba běhu Shellsortu je silně závislá na sekvenci mezer, kterou používá. U mnoha praktických variant zůstává určení jejich časové náročnosti otevřeným problémem .
Popis
Shellsort je optimalizace typu vkládání, která umožňuje výměnu položek, které jsou daleko od sebe. Cílem je uspořádat seznam prvků tak, aby počínaje kdekoli, každý h th prvek vytvořil seřazený seznam. Takový seznam je prý h -tříděný. Lze jej také považovat za h proložené seznamy, každý jednotlivě seřazený. Počínaje velkými hodnotami h umožňuje prvkům pohybovat se v původním seznamu na dlouhé vzdálenosti, což rychle snižuje velké množství nepořádku a ponechává méně práce pro menší h -sort kroky. Pokud je seznam potom k -seřazen pro nějaké menší celé číslo k , pak seznam zůstane h -sorted. Podle této myšlenky na klesající posloupnost hodnot h končících na 1 je zaručeno, že na konci zůstane seřazený seznam.
Zjednodušeně to znamená, že pokud máme pole 1024 čísel, naše první mezera ( h ) by mohla být 512. Poté procházíme seznamem a porovnáváme každý prvek v první polovině s prvkem ve druhé polovině. Naše druhá mezera ( k ) je 256, což rozděluje pole na čtyři sekce (počínaje 0,256,512,768), a my se ujistíme, že první položky v každé sekci jsou vzájemně seřazeny, pak druhá položka v každé sekci atd. . V praxi může být sekvence mezery cokoli, ale poslední mezera je vždy 1 pro dokončení třídění (efektivní dokončení obyčejným vložením).
Níže je uveden příklad běhu Shellsortu s mezerami 5, 3 a 1.
| a 1 | a 2 | a 3 | a 4 | a 5 | a 6 | a 7 | a 8 | a 9 | a 10 | a 11 | a 12 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Vstupní data | 62 | 83 | 18 | 53 | 07 | 17 | 95 | 86 | 47 | 69 | 25 | 28 |
| Po 5-třídění | 17 | 28 | 18 | 47 | 07 | 25 | 83 | 86 | 53 | 69 | 62 | 95 |
| Po třídění | 17 | 07 | 18 | 47 | 28 | 25 | 69 | 62 | 53 | 83 | 86 | 95 |
| Po 1-třídění | 07 | 17 | 18 | 25 | 28 | 47 | 53 | 62 | 69 | 83 | 86 | 95 |
První průchod, třídění, provádí třídění vkládání na pět samostatných podoblastí ( a 1 , a 6 , a 11 ), ( a 2 , a 7 , a 12 ), ( a 3 , a 8 ), ( a 4 , a 9 ), ( a 5 , a 10 ). Například změní podoblast ( a 1 , a 6 , a 11 ) z (62, 17, 25) na (17, 25, 62). Další průchod, třídění, provede třídění vložení na tři dílčí pole ( a 1 , a 4 , a 7 , a 10 ), ( a 2 , a 5 , a 8 , a 11 ), ( a 3 , a 6 , a 9 , a 12 ). Poslední průchod, 1-třídění, je obyčejný vkládací druh celého pole ( a 1 , ..., a 12 ).
Jak ukazuje příklad, dílčí pole, na kterých Shellsort pracuje, jsou zpočátku krátká; později jsou delší, ale téměř objednané. V obou případech funguje třídění vkládání efektivně.
Shellsort není stabilní : může změnit relativní pořadí prvků se stejnými hodnotami. Jedná se o algoritmus adaptivního řazení v tom, že se provádí rychleji, když je vstup částečně seřazen.
Pseudo kód
Použití mezerové sekvence Marcina Ciury s vnitřním zařazením.
# Sort an array a[0...n-1].
gaps = [701, 301, 132, 57, 23, 10, 4, 1] // Ciura gap sequence
# Start with the largest gap and work down to a gap of 1
foreach (gap in gaps)
{
# Do a gapped insertion sort for this gap size.
# The first gap elements a[0..gap-1] are already in gapped order
# keep adding one more element until the entire array is gap sorted
for (i = gap; i < n; i += 1)
{
# add a[i] to the elements that have been gap sorted
# save a[i] in temp and make a hole at position i
temp = a[i]
# shift earlier gap-sorted elements up until the correct location for a[i] is found
for (j = i; j >= gap and a[j - gap] > temp; j -= gap)
{
a[j] = a[j - gap]
}
# put temp (the original a[i]) in its correct location
a[j] = temp
}
}
Sekvence mezer
Otázka rozhodnout, kterou sekvenci mezer použít, je obtížná. Každá mezerová sekvence, která obsahuje 1, poskytuje správné řazení (protože to činí konečný průchod obyčejným vkládacím tříděním); vlastnosti takto získaných verzí Shellsortu se však mohou velmi lišit. Příliš málo mezer zpomaluje přihrávky a příliš mnoho mezer vytváří režii.
Níže uvedená tabulka porovnává většinu dosud navržených sekvencí mezer. Některé z nich mají klesající prvky, které závisí na velikosti tříděného pole ( N ). Jiné zvyšují nekonečné sekvence, jejichž prvky menší než N by měly být použity v opačném pořadí.
| OEIS | Obecný termín ( k ≥ 1) | Betonové mezery | Časová složitost v nejhorším případě |
Autor a rok vydání |
|---|---|---|---|---|
| [např. když N = 2 p ] | Shell , 1959 | |||
| Frank & Lazarus, 1960 | ||||
| A000225 | Hibbard , 1963 | |||
| A083318 | s předponou 1 | Papernov a Staševič, 1965 | ||
| A003586 | Po sobě jdoucí čísla formuláře ( 3 hladká čísla) | Pratt , 1971 | ||
| A003462 | , ne větší než | Knuth , 1973, podle Pratt , 1971 | ||
| A036569 | Incerpi & Sedgewick , 1985, Knuth | |||
| A036562 | s předponou 1 | Sedgewick, 1982 | ||
| A033622 | Sedgewick, 1986 | |||
| Neznámý | Gonnet & Baeza-Yates , 1991 | |||
| A108870 | Neznámý | Tokuda, 1992 | ||
| A102549 | Neznámý (experimentálně odvozený) | Neznámý | Ciura, 2001 |
Když binární reprezentace N obsahuje mnoho po sobě jdoucích nul, Shellsort pomocí Shellovy původní mezerové sekvence provede srovnání Θ ( N 2 ) v nejhorším případě. Například tento případ nastává pro N rovný síle dvou, když prvky větší a menší než medián zaujímají liché a sudé pozice, protože jsou porovnávány pouze v posledním průchodu.
Přestože má Prattova verze vyšší složitost než O ( N log N ), která je optimální pro srovnávací druhy, je vhodná k třídění sítí a má stejnou asymptotickou složitost brány jako Batcherův bitonický třídič .
Gonnet a Baeza-Yates zjistili, že Shellsort provádí v průměru nejméně srovnání, když jsou poměry po sobě jdoucích mezer zhruba stejné jako 2,2. Proto se jejich sekvence s poměrem 2,2 a Tokudova sekvence s poměrem 2,25 ukázala jako účinná. Není však známo, proč tomu tak je. Sedgewick doporučuje použít mezery, které mají nízké největší společné dělitele nebo jsou párové coprime .
S ohledem na průměrný počet srovnání má sekvence Ciury nejznámější výkon; mezery ze 701 nebyly stanoveny, ale sekvenci lze dále prodloužit podle rekurzivního vzorce .
Tokuda je sekvence, které jsou definovány pomocí jednoduchého vzorce , kde , , lze doporučit pro praktické aplikace.
Pokud je maximální velikost vstupu malá, což může nastat, pokud je Shellsort používán na malých dílčích polích jiným algoritmem rekurzivního řazení, jako je rychlé řazení nebo sloučení , pak je možné pro každou velikost vstupu vytvořit tabulku s optimální sekvencí.
Výpočetní náročnost
Platí následující vlastnost: po h 2 -třídění jakéhokoli h 1 -tříděného pole, pole zůstane h 1 -tříděno. Každý h 1 -sorted a h 2 -sorted pole je také ( 1 h 1 + 2 H 2 ) -sorted, pro jakékoliv nezáporné celá čísla 1 a 2 . Složitost Shellsortu v nejhorším případě je tedy spojena s Frobeniusovým problémem : pro daná celá čísla h 1 , ..., h n s gcd = 1 je Frobeniusovo číslo g ( h 1 , ..., h n ) největší celé číslo, které nemohou být reprezentován jako v 1 h 1 + ... + n h n s nezáporné celé číslo z 1 , ..., a n . Pomocí známých vzorců pro čísla Frobenius můžeme určit nejhorší složitost Shellsortu pro několik tříd mezerových sekvencí. Osvědčené výsledky jsou uvedeny ve výše uvedené tabulce.
Pokud jde o průměrný počet operací, žádný z prokázaných výsledků se netýká praktické mezery. Pro mezery, které jsou mocninami dvou, vypočítal Espelid tento průměr jako . Knuth určil průměrnou složitost třídění pole N -prvku se dvěma mezerami ( h , 1) na . Z toho vyplývá, že dvouprůchodový Shellsort s h = Θ ( N 1/3 ) činí v průměru O ( N 5/3 ) srovnání/inverze/doba běhu. Yao zjistil průměrnou složitost tříprůchodového Shellsortu. Jeho výsledek zpřesnili Janson a Knuth: průměrný počet srovnání/inverzí/doby běhu provedeného během Shellsortu se třemi mezerami ( ch , cg , 1), kde h a g jsou coprime, je v prvním průchodu, ve druhém přihrávka a ve třetím průchodu. ψ ( h , g ) v posledním vzorci je komplikovaná funkce asymptoticky rovná . Zejména když h = Θ ( N 7/15 ) a g = Θ ( N 1/5 ), průměrná doba třídění je O ( N 23/15 ).
Na základě experimentů, to je se domníval, že ShellSort s Hibbard je mezera sekvence běží v O ( N 5/4 ) průměrná doba, a že Gonnet a Baeza-Yates Sekvence vyžaduje v průměru o 0,41 N ln N (ln ln N + 1/6 ) prvek se pohybuje. Přibližování průměrného počtu operací dříve předložených pro jiné sekvence selže, když seřazená pole obsahují miliony prvků.
Níže uvedený graf ukazuje průměrný počet porovnání prvků v různých variantách Shellsortu dělený teoretickou dolní mezí, tj. Log 2 N !, Kde byla rozšířena sekvence 1, 4, 10, 23, 57, 132, 301, 701 podle vzorce .
Použitím teorie Kolmogorovovy složitosti prokázali Jiang, Li a Vitányi následující dolní mez pro pořadí průměrného počtu operací/ doby běhu v p -pass Shellsort: Ω ( pN 1+1/ p ), když p ≤ log 2 N a Ω ( pN ), když p > log 2 N . Shellsort má proto vyhlídky na běh v průměrném čase, který asymptoticky roste jako N log N pouze při použití sekvencí mezer, jejichž počet mezer roste úměrně k logaritmu velikosti pole. Není však známo, zda Shellsort dokáže dosáhnout tohoto asymptotického řádu složitosti průměrných případů, které je optimální pro srovnávací druhy. Dolní hranice se zlepšila Vitányi pro každé počtu průchodů do kde . Tento výsledek implikuje například dolní hranici Jiang-Li-Vitányiho pro all-pass přírůstkové sekvence a zlepšuje tuto spodní hranici pro konkrétní přírůstkové sekvence. Ve skutečnosti jsou všechny meze (dolní a horní), které jsou v současné době známé pro průměrný případ, přesně shodné s touto dolní hranicí. Například to dává nový výsledek, že horní hranice Janson-Knuth je shodná s výslednou dolní mezí pro použitou přírůstkovou sekvenci, což ukazuje, že tříprůchodový Shellsort pro tuto přírůstkovou sekvenci používá srovnání/inverze/doba běhu. Vzorec nám umožňuje hledat přírůstkové sekvence, které dávají dolní hranice, které nejsou známy; například přírůstková sekvence pro čtyři průchody, která má spodní hranici větší než pro přírůstkovou sekvenci . Dolní mez se stává
Složitost nejhoršího případu jakékoli verze Shellsortu je vyššího řádu: Plaxton, Poonen a Suel ukázali, že roste minimálně stejně rychle jako .
Aplikace
Shellsort provádí více operací a má vyšší poměr chyb mezipaměti než quicksort . Jelikož jej však lze implementovat pomocí malého kódu a nepoužívá zásobník volání , některé implementace funkce qsort ve standardní knihovně C cílené na vestavěné systémy ji používají místo quicksortu. Shellsort se například používá v knihovně uClibc . Z podobných důvodů byl v minulosti v jádře Linuxu používán Shellsort .
Shellsort může také sloužit jako subalgoritmus introspektivního třídění , k třídění krátkých dílčích polí a k prevenci zpomalení, když hloubka rekurze překročí danou mez. Tento princip se používá například v kompresoru bzip2 .
Viz také
Reference
Bibliografie
- Knuth, Donald E. (1997). „Shellova metoda“. Umění počítačového programování. Svazek 3: Třídění a vyhledávání (2. vyd.). Reading, Massachusetts: Addison-Wesley. s. 83–95. ISBN 978-0-201-89685-5.
- Analýza Shellsortu a souvisejících algoritmů , Robert Sedgewick, Čtvrté evropské sympozium o algoritmech, Barcelona, září 1996.
externí odkazy
- Algoritmy animovaného řazení: Shell Sort na Wayback Machine (archivováno 10. března 2015) - grafická ukázka
- Shellsort s mezerami 5, 3, 1 jako maďarský lidový tanec
