Shellsort - Shellsort

Shellsort
Shellsortin visualisointi vaihe vaiheelta
Kuori, jossa on aukkoja 23, 10, 4, 1 toiminnassa
Luokka Lajittelualgoritmi
Tietorakenne Array
Huonoin suoritus O ( n 2 ) (pahin tunnettu pahimman tapauksen aukkosekvenssi)
O ( n log 2 n ) (tunnetuin pahin tapausjakso)
Paras esitys O ( n log n ) (useimmat aukkosekvenssit)
O ( n log 2 n ) (tunnetuin pahimmassa tapauksessa oleva aukkosekvenssi)
Keskimääräinen suorituskyky riippuu välijärjestyksestä
Pahimmassa tapauksessa tilan monimutkaisuus О ( n ) yhteensä, O (1) apulaite
Shellsortin vaiheet.
Kohdeparien vaihtaminen Shellsortin peräkkäisissä vaiheissa aukkojen 5, 3, 1 kanssa

Shellsort , joka tunnetaan myös nimellä Shell-lajittelu tai Shell-menetelmä , on paikan päällä oleva vertailulaji . Sitä voidaan pitää joko yleistyksenä lajittelun vaihdon ( kuplalajittelu ) tai lajittelun lisäämisen ( lisäyslajittelu ) perusteella. Menetelmä alkaa lajittelemalla elementtiparit kaukana toisistaan ​​ja pienentämällä asteittain vertailtavien elementtien välistä kuilua. Aloittamalla kaukana toisistaan ​​olevista elementeistä, se voi siirtää jotkut paikoillaan olevat elementit paikalleen nopeammin kuin yksinkertainen lähimmän naapurin vaihto. Donald Shell julkaisi ensimmäisen tällaisen version vuonna 1959. Shellsortin käyttöaika riippuu suuresti käyttämästään aukkojärjestyksestä. Monien käytännön varianttien osalta niiden monimutkaisuuden määrittäminen on edelleen avoin ongelma .

Kuvaus

Shellsort on optimointi lisäyslajittelun joka mahdollistaa vaihdon kohteita, jotka ovat kaukana toisistaan. Ajatuksena on järjestää elementtiluettelo niin, että mistä tahansa alkaen jokaisen h : n elementin ottaminen tuottaa lajitellun luettelon. Tällaisen luettelon sanotaan olevan h -lajiteltu. Sitä voidaan myös ajatella h lomitetuina luetteloina, joista jokainen on lajiteltu erikseen. Suurista h -arvoista alkaen elementit voivat liikkua pitkiä matkoja alkuperäisessä luettelossa, mikä vähentää suuria häiriöitä nopeasti ja jättää vähemmän työtä pienemmille h -lajitteluvaiheille. Jos luettelo on sitten k -lajiteltu jollekin pienemmälle kokonaisluvulle k , luettelo pysyy h -lajiteltuna. Tämän ajatuksen noudattaminen h -arvojen pienenevässä sarjassa, joka päättyy 1: een, jättää varmasti lajiteltu luettelo loppuun.

Yksinkertaistettuna tämä tarkoittaa, että jos meillä on 1024 -numeroinen taulukko, ensimmäinen aukko ( h ) voisi olla 512. Käymme sitten luettelon läpi vertaamalla jokaisen ensimmäisen puoliskon elementtiä toisen puoliskon elementtiin. Toinen aukko ( k ) on 256, joka jakaa taulukon neljään osaan (alkaen 0,256,512,768), ja varmistamme, että kunkin osion ensimmäiset kohteet on lajiteltu suhteessa toisiinsa, sitten toinen kohde kussakin osassa ja niin edelleen . Käytännössä aukkosekvenssi voi olla mikä tahansa, mutta viimeinen väli on aina 1 lajittelun viimeistelemiseksi (viimeistely käytännössä tavallisella lisäyslajittelulla).

Alla on esimerkki Shellsortista, jossa on aukot 5, 3 ja 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
Syöttötiedot 62 83 18 53 07 17 95 86 47 69 25 28
5 lajittelun jälkeen 17 28 18 47 07 25 83 86 53 69 62 95
3-lajittelun jälkeen 17 07 18 47 28 25 69 62 53 83 86 95
1-lajittelun jälkeen 07 17 18 25 28 47 53 62 69 83 86 95

Ensimmäinen siirto, 5-lajittelu, suorittaa lisäyslajittelun viidellä erillisellä alitasolla ( a 1 , a 6 , a 11 ), ( a 2 , a 7 , a 12 ), ( a 3 , a 8 ), ( a 4 , a 9 ), ( 5 , 10 ). Se esimerkiksi muuttaa aliryhmän ( a 1 , a 6 , a 11 ) arvosta (62, 17, 25) arvoon (17, 25, 62). Seuraavan pass, 3-lajittelu, suorittaa se pistetään lajitella kolme alijärjestelyt ( 1 , 4 , 7 , 10 ), ( 2 , 5 , 8 , 11 ), ( 3 , 6 , 9 , 12 ). Viimeinen siirto, 1-lajittelu, on tavallinen lisäyslaji koko ryhmästä ( a 1 , ..., a 12 ).

Kuten esimerkki havainnollistaa, Shellsortin käyttämät alirivit ovat aluksi lyhyitä; myöhemmin ne ovat pidempiä, mutta melkein tilattuja. Molemmissa tapauksissa lisäyslajittelu toimii tehokkaasti.

Shellsort ei ole vakaa : se voi muuttaa elementtien suhteellista järjestystä yhtä suurilla arvoilla. Se on mukautuva lajittelualgoritmi , koska se suorittaa nopeammin, kun tulo on osittain lajiteltu.

Pseudokoodi

Käyttämällä Marcin Ciuran aukkosekvenssiä sisäisellä lisäyslajikkeella.

# 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
    }
}

Gap -sekvenssit

Kysymys siitä, mitä aukkoa käytetään, on vaikea päättää. Jokainen aukkosarja, joka sisältää yhden, antaa oikean lajittelun (koska tämä tekee viimeisestä passista tavallisen lisäyslajittelun); näin saatujen Shellsort -versioiden ominaisuudet voivat kuitenkin olla hyvin erilaisia. Liian vähän aukkoja hidastaa syöttöjä ja liian monet aukot aiheuttavat yleiskustannuksia.

Alla olevassa taulukossa verrataan useimpia tähän mennessä julkaistuja ehdotettuja aukkosekvenssejä. Joissakin niistä on pieneneviä elementtejä, jotka riippuvat lajiteltujen matriisien ( N ) koosta . Toiset lisäävät äärettömiä sekvenssejä, joiden elementtejä, jotka ovat pienempiä kuin N, tulisi käyttää päinvastaisessa järjestyksessä.

OEIS Yleinen termi ( k ≥ 1) Betoniset aukot Pahimman
ajan monimutkaisuus
Tekijä ja julkaisuvuosi
[esim. kun N = 2 p ] Shell , 1959
Frank & Lazarus, 1960
A000225 Hibbard , 1963
A083318 , etuliite 1 Papernov & Stasevich, 1965
A003586 Lomakkeen peräkkäiset numerot ( 3 tasaista numeroa) Pratt , 1971
A003462 , ei suurempi kuin Knuth , 1973, perustuu Pratt , 1971
A036569 Incerpi & Sedgewick , 1985, Knuth
A036562 , etuliite 1 Sedgewick, 1982
A033622 Sedgewick, 1986
Tuntematon Gonnet & Baeza-Yates , 1991
A108870 Tuntematon Tokuda, 1992
A102549 Tuntematon (kokeellisesti johdettu) Tuntematon Ciura, 2001

Kun binääriesityksen N sisältää useita peräkkäisiä nollia, Shellsort käyttäen Shellin alkuperäinen aukko sekvenssi tekee Θ ( N 2 ) vertailut pahimmassa tapauksessa. Esimerkiksi tämä tapaus esiintyy N: lle, joka on yhtä suuri kuin kaksi voimaa, kun mediaania suurempia ja pienempiä elementtejä on pariton ja parillinen, vastaavasti, koska niitä verrataan vasta viimeisellä siirtymällä.

Vaikka Prattin versio on monimutkaisempi kuin O ( N  log  N ), joka on optimaalinen vertailulajeille, Prattin versio soveltuu lajitteluverkkoihin ja sillä on sama asymptoottinen portin monimutkaisuus kuin Batcherin bitonilajittelulla .

Gonnet ja Baeza-Yates havaitsivat, että Shellsort tekee keskimäärin vähiten vertailuja, kun peräkkäisten aukkojen suhde on suunnilleen 2,2. Siksi niiden sekvenssi suhteella 2.2 ja Tokudan sekvenssi suhteella 2,25 osoittautuvat tehokkaiksi. Ei kuitenkaan tiedetä, miksi näin on. Sedgewick suosittelee sellaisten aukkojen käyttämistä, joilla on pienimmät suurimmat yhteiset jakajat tai jotka ovat pareittain kopioituja .

Vertailujen keskimääräisen määrän osalta Ciuran sekvenssillä on tunnetuin suorituskyky; aukkoja 701: stä ei määritetty, mutta sekvenssiä voidaan edelleen pidentää rekursiivisen kaavan mukaisesti .

Tokudan sekvenssi, joka määritellään yksinkertaisella kaavalla , missä , voidaan suositella käytännön sovelluksiin.

Jos syötteen enimmäiskoko on pieni, kuten voi tapahtua, jos Shellsortia käytetään pienissä alijoukoissa toisessa rekursiivisessa lajittelualgoritmissa, kuten pikalähetys- tai yhdistämislajittelussa , on mahdollista taulukoittaa optimaalinen sekvenssi jokaiselle syöttökoolle.

Laskennallinen monimutkaisuus

Seuraava ominaisuus pätee: minkä tahansa h 1 -lajitelman matriisin h 2 -lajittelun jälkeen taulukko pysyy h 1 -lajiteltuna. Jokainen h 1 -sorted ja h 2 -sorted matriisi on myös ( 1 h 1 + 2 h 2 ) -sorted, mitään negatiivisia kokonaislukuja 1 ja 2 . Shellsortin pahin tapaus liittyy siis Frobenius-ongelmaan : annetuille kokonaisluvuille h 1 , ..., h n, joiden gcd = 1, Frobenius-luku g ( h 1 , ..., h n ) on suurin kokonaisluku, joka ei ole edustettuina 1 h 1 + ... + n h n kanssa positiivinen kokonaisluku 1 , ..., n . Käyttämällä Frobenius-numeroiden tunnettuja kaavoja voimme määrittää Shellsortin pahimman monimutkaisuuden useille aukkosekvenssiluokille. Todistetut tulokset on esitetty yllä olevassa taulukossa.

Toimenpiteiden keskimääräisen määrän osalta mikään todistetuista tuloksista ei koske käytännön aukkosekvenssiä. Espelid laski tämän keskiarvon välille, jotka ovat kahden voimia . Knuth määritteli N -elementtimatriisin, jossa on kaksi aukkoa ( h , 1), keskimääräisen monimutkaisuuden olla . Tästä seuraa, että kaksikierroksinen Shellsort, jossa h = Θ ( N 1/3 ), tekee keskimäärin O ( N 5/3 ) vertailuja/käänteisiä/ajoaikaa. Yao löysi Shellsortin kolmiportaisen keskimääräisen monimutkaisuuden. Hänen tulostaan ​​tarkensivat Janson ja Knuth: Shellsortin aikana tehtyjen kolmen aukon ( ch , cg , 1) aikana tehtyjen vertailujen/inversioiden/ajoajan keskimääräinen lukumäärä ( ch , cg , 1), jossa h ja g ovat kopiokoneita, on ensimmäisellä kierroksella, toisella pass ja kolmannessa. ψ ( h , g ) viimeisessä kaavassa on monimutkainen funktio, joka on asymptoottisesti yhtä suuri kuin . Erityisesti kun h = Θ ( N 7/15 ) ja g = Θ ( N 1/5 ), keskimääräinen lajitteluaika on O ( N 23/15 ).

Kokeiden perusteella arvellaan, että Shellsort kanssa Hibbard n aukko sekvenssi kulkee O ( N 5/4 ) keskimääräinen aika, ja että Gonnet ja Baeza-Yates sekvenssin vaatii keskimäärin 0,41 N  ln  N  (ln ln  N  + 1/6 ) elementti liikkuu. Muille sekvensseille aiemmin esitettyjen operaatioiden keskimääräisen määrän arvioinnit epäonnistuvat, kun lajitellut taulukot sisältävät miljoonia elementtejä.

Alla olevassa kaaviossa esitetään elementtien vertailujen keskimääräinen lukumäärä Shellsortin eri muunnelmissa jaettuna teoreettisella alarajalla, eli log 2 N !, Jossa sekvenssiä 1, 4, 10, 23, 57, 132, 301, 701 on laajennettu kaavan mukaan .

Shell lajittelee keskimääräisen vertailumäärän (englanti). Svg

Sovellettaessa Kolmogorovin monimutkaisuuden teoriaa Jiang, Li ja Vitányi osoittivat seuraavan alarajan p -pass Shellsort -operaatioiden keskimääräisen lukumäärän/ käyntiajan järjestykselle: Ω ( pN 1+1/ p ), kun p  ≤ log 2 N ja Ω ( pN ), kun p  > log 2 N . Siksi Shellsortilla on mahdollisuus suorittaa keskimääräinen aika, joka kasvaa asymptoottisesti N log N: n tavoin vain käytettäessä aukkosekvenssejä, joiden aukkojen määrä kasvaa suhteessa taulukon koon logaritmiin. On kuitenkin epäselvää, pystyykö Shellsort saavuttamaan tämän keskimääräisen tapauksen monimutkaisuuden asymptoottisen järjestyksen, joka on optimaalinen vertailulajeille. Alarajan paransi Vitányi jokaista ajokertojen ja missä . Tämä tulos tarkoittaa esimerkiksi Jiang-Li-Vitányin alarajaa all- pass -lisäyssekvensseille ja parantaa sitä alarajaa tietyille lisäyssekvensseille . Itse asiassa kaikki rajat (alempi ja ylempi), jotka tällä hetkellä tunnetaan keskimääräisestä tapauksesta, vastaavat tarkasti tätä alarajaa. Tämä antaa esimerkiksi uuden tuloksen, että Janson-Knuthin yläraja vastaa käytetyn lisäyssekvenssin tuloksena olevaa alarajaa, mikä osoittaa, että kolmen lisäyksen Shellsort käyttää tätä lisäyssekvenssiä vertailuja/käänteisiä/ajoaikaa. Kaavan avulla voimme etsiä lisäsekvenssejä, jotka tuottavat alempia rajoja, joita ei tunneta; esimerkiksi neljän jakson lisäyssekvenssi, jonka alaraja on suurempi kuin lisäyssekvenssillä . Alaraja muuttuu

Pahimman tapauksen monimutkaisuuteen mitään versiota Shellsort on korkeamman asteen: Plaxton, Poonen ja Suel osoitti, että se kasvaa vähintään yhtä nopeasti kuin .

Sovellukset

Shellsort suorittaa enemmän toimintoja ja välimuistin missaussuhde on korkeampi kuin quicksort . Koska se voidaan toteuttaa käyttämällä vähän koodia ja ei käytä kutsupino , jotkut toteutukset qsort funktion C standardin kirjasto suunnattu sulautettujen järjestelmien käyttää sen sijaan quicksort. Shellsortia käytetään esimerkiksi uClibc -kirjastossa. Samoista syistä Shellsortia käytettiin aiemmin Linux -ytimessä .

Shellsort voi myös toimia introspektiivisen lajittelun alialgoritmina , lajitella lyhyitä aliryhmiä ja estää hidastumisen, kun rekursiosyvyys ylittää tietyn rajan. Tätä periaatetta käytetään esimerkiksi bzip2 -kompressorissa.

Katso myös

Viitteet

Bibliografia

Ulkoiset linkit