Shelli sortimine

Shelli sortimine (ka väheneva sammu meetod) on sortimisalgoritm, mis töötab kohapeal (s.t. ei vaja abiandmestruktuure) ja põhineb elementide võrdlusel. Shelli sortimisalgoritmi vaadeldakse tavaliselt pistemeetodi variatsioonina, kus võrreldakse ja vahetatakse ka üksteisest kaugel asuvaid elemente. Algoritmi käigus sorditakse esmalt elemendid, mis asuvad üksteisest suure fikseeritud sammu kaugusel, seejärel vähendatakse järk-järgult sorditavate elementide vahelist sammu. Suure sammuga alustamine võimaldab mõned elemendid viia oma õigele positsioonile kiiremini kui ainult kõrvuti asuvate elementide vahetamine. Algoritmi esimese versiooni avaldas Donald Shell 1959. aastal. Shelli sortimise idee seisneb loendi elementide ümberpaigutamises nii, et võttes mistahes positsioonist alustades iga h-nda elemendi, saadakse sorditud alamloend. Sel juhul öeldakse, et loend on h-sorditud. Suurte h väärtustega alustamine võimaldab liigutada elementide kaugetele positsioonidele, vähendades kiiresti valejärjestusi. Kui loend on k-sorditud mingi täisarvu k < h korral, siis loend jääb ka h-sordituks. Vähendades sammu h arvuni 1, saadakse tulemuseks alati sorditud loend. Alljärgnev on näide Shelli sortimisest sammudega 5, 3 ja 1. Esimesel läbimisel sorditakse pistemeetodil alamloendid, mille elementide indeksid algses loendis erinevad 5 võrra: (a1, a6, a11), (a2, a7, a12), (a3, a8), (a4, a9), (a5, a10). Näiteks on alamloend (a1, a6, a11) ehk (62, 17, 25) pärast sortimist (17, 25, 62). Järgmisel läbimisel sorditakse alamloendid (a1, a4, a7, a10), (a2, a5, a8, a11), (a3, a6, a9, a12). Viimasel läbimisel sorditakse kogu loend (a1,..., a12) tavalise pistemeetodiga. Näide illustreerib, kuidas Shelli sortimisel on alamloendid algul lühikesed ja hiljem pikad, kuid peaaegu sorditud. Mõlemal juhul töötab tavaline pistemeetod efektiivselt. Shelli sortimine ei ole stabiilne: võrdsete elementide korral võib nende omavaheline järjestus tulla erinev. Shelli sortimisalgoritm on adaptiivne ehk selle tööaeg on lühem loenditel, mis on juba osaliselt sorditud. Koodis on kasutatakse Marcin Ciura sammude jada ja sisemise sortimismeetodina pistemeetodit. # Olgu sorditavaks loendiks a[0...n-1]. gaps = [701, 301, 132, 57, 23, 10, 4, 1] # Alustame suurima sammuga ja lõpetame sammuga 1. foreach (gap in gaps) { # Sordime üksteisest käesoleva sammu kaugusel asuvad elemendid. # Esimese sammu elemendid a[0..gap-1] on juba sammu järgi sorditud. # Lisame ühe elemendi kaupa, kuni kogu loend on sammu järgi sorditud. for (i = gap; i < n; i += 1) { # Lisame a[i] sammuga sorditud elementide hulka. # Salvestame a[i] abimuutujasse temp, et vabastada positsioon i. temp = a[i] # Nihutame varasemaid sammuga sorditud elemente, kuni leiame a[i] õige positsiooni. for (j = i; j >= gap and a[j - gap] > temp; j -= gap) { a[j] = a[j - gap] } # Paneme abimuutuja (originaalse a[i]) õigele positsioonile. a[j] = temp } } Shelli sortimisalgoritmi ajaline keerukus sõltub valitud sammupikkuste jadast. Tõestatult parimat võimalikku sammujada ei ole leitud. Iga sammujada, mis lõpeb sammuga 1, annab Shelli sortimise tulemuseks korrektselt sorditud loendi. Alljärgnev tabel võrdleb levinumaid seni avaldatud sammujadasid. Mõned neist on kasvavad lõpmatud jadad, mille elemendid, mis on väiksemad kui N, tuleb võtta vastupidises (kahanevas) järjekorras. Kui arvu N kahendesituses esineb palju järjestikuseid nulle, tehakse sortimisel Shelli originaalse sammujadaga halvimal juhul Θ(N2) võrdlust. Selline juht ilmneb näiteks siis, kui N on võrdne arvu 2 mingi astmega ja mediaanist suuremad elemendid on paaritutel positsioonidel ning väiksemad paaris positsioonidel, kuna siis võrreldakse neid alles viimasel läbimisel. Keskmise võrdluste arvu poolest on teadaolevalt parima jõudlusega Ciura jada, kus sammupikkused üle 701 saab välja arvutada üldvalemiga h k = ⌊ 2.25 h k − 1 ⌋ {\displaystyle h_{k}=\lfloor 2.25h_{k-1}\rfloor } . Shelli sortimine teeb rohkem võrdlusi ja sellel on suurem vahemälu möödalask kui kiirsortimisel, kuid selle implementatsioon on lühike ja see ei kasuta kutsepinu. Seetõttu on Shelli sortimine kasutusel mõnes qsort funktsiooni implementatsioonis C standardteegis, mis on suunatud manussüsteemidele. Sarnastel põhjustel oli Shelli sortimine varem kasutusel Linuxi kernelis. Shelli sortimist võib kasutada introsort algoritmis, et sortida lühikesi alamloendeid ja vältida algoritmi aeglustumist, kui rekursioon saavutab teatud sügavuse. Sel põhimõttel töötab näiteks bzip2 kompressor. Robert Sedgewick (1998). Algorithms in C (inglise). Kd 1 (3. trükk). Addison-Wesley. Lk 273–281. ISBN 978-0-201-31452-6. Shell, D. L. (1959). "A High-Speed Sorting Procedure". Communications of the ACM (inglise). 2 (7): 30–32. DOI:10.1145/368370.368387. ISSN 0001-0782. Donald E. Knuth (1997). The Art of Computer Programming. Volume 3: Sorting and Searching (2. trükk). Reading, Massachusetts: Addison-Wesley. Lk 83–95. ISBN 978-0-201-89685-5. Bharadwaj, Ashutosh; Mishra, Shailendra (2013). "Comparison of Sorting Algorithms based on Input Sequences" (PDF). International Journal of Computer Applications. 78 (14): 7–10. DOI:10.5120/13589-1325. Sedgewick, Robert (1996). "Analysis of Shellsort and Related Algorithms". Fourth European Symposium on Algorithms (inglise). DOI:10.1007/3-540-61680-2_42. Frank, R. M.; Lazarus, R. B. (1960). "A High-Speed Sorting Procedure". Communications of the ACM (inglise). 3 (1): 20–22. DOI:10.1145/366947.366957. ISSN 0001-0782. Hibbard, Thomas N. (1963). "An empirical study of minimal storage sorting". Communications of the ACM (inglise). 6 (5): 206–213. DOI:10.1145/366552.366557. ISSN 0001-0782. Papernov, A. A.; Stasevich, G. V. (1965). "A Method of Information Sorting in Computer Memories" (PDF). Problems of Information Transmission. 1 (3): 63–75. Pratt, Vaughan R. (1979). Shellsort and sorting networks. New York: Garland Pub. ISBN 0-8240-4406-1. Incerpi, Janet; Sedgewick, Robert (1985). "Improved upper bounds on shellsort". Journal of Computer and System Sciences (inglise). 31 (2): 210–224. DOI:10.1016/0022-0000(85)90042-X. Sedgewick, Robert (1986). "A new upper bound for Shellsort". Journal of Algorithms (inglise). 7 (2): 159–173. DOI:10.1016/0196-6774(86)90001-5. Gonnet, G. H. (Gaston H.) (1984). Handbook of algorithms and data structures. London: Addison-Wesley Pub. Co. ISBN 0-201-14218-X. Tokuda, N. (1992). "An Improved Shellsort". Proceedings of the IFIP 12th World Computer Congress on Algorithms, Software, Architecture. Amsterdam: North-Holland Publishing Co. Lk 449–457. Ciura, M. (2001). "Best Increments for the Average Case of Shellsort". Proceedings of the 13th International Symposium on Fundamentals of Computation Theory. London: Springer-Verlag. Lk 106–117. ISBN 978-3-540-42487-1. "kernel/groups.c". Vaadatud 7.12.2020.{{cite web}}: CS1 hooldus: url-olek (link) Julian Seward. "bzip2/blocksort.c". Vaadatud 7.12.2020.{{cite web}}: CS1 hooldus: url-olek (link)