811312A Tietorakenteet ja algoritmit 2016-2017 III Lajittelualgoritmeista
Sisältö 1. Johdanto 2. Pikalajittelu 3. Kekolajittelu 4. Lajittelualgoritmien suorituskyvyn rajoista 811312A TRA, Lajittelualgoritmeista 2
III.1 Johdanto: Miksi perehtyä lajitteluun Lajittelua käytetään osana monissa algoritmeissa: Lajittelualgoritmien tunteminen auttaa muiden ongelmien ratkaisussa Lajittelualgoritmeihin perehtymällä oppii algoritmien suunnittelutekniikoita Lajittelu on tutkituin tietojenkäsittelytieteen algoritminen ongelma: tunnetaan kymmeniä algoritmeja 811312A TRA, Lajittelualgoritmeista 3
III.2 Pikalajittelu (Quicksort) Keksijä C. A. R. Hoare (Ks. Hoare: Quicksort. Computer Journal, 5(1):10 15, 1962) Käytännössä hyvin nopea lajittelualgoritmi Perustuu hajota ja hallitse -periaatteeseen (kuten lomituslajittelukin) Aineisto jaetaan kahteen osaan, joista toisessa on sarana-alkiota (pivot) arvoltaan pienemmät alkiot ja toisessa vastaavasti suuremmat Osat jaetaan edelleen samalla tavalla rekursiivisesti kahteen osaan jne. Lajittelee taulukon paikallaan Algoritmi PARTITION jakaa aineiston vaaditulla tavalla kahteen osaan 811312A TRA, Lajittelualgoritmeista 4
III.2.1 Pikalajittelun algoritmi Syöte: Taulukon osa A[p,..,r] Tuloste: A[p,..,r] lajiteltuna järjestykseen pienimmästä suurimpaan QUICKSORT(A, p, r) 1. if p < r 2. q = PARTITION(A, p, r) 3. QUICKSORT(A, p, q-1) 4. QUICKSORT(A, q+1, r) 811312A TRA, Lajittelualgoritmeista 5
III.2.1 Pikalajittelun algoritmi (2) Syöte: Taulukon osa A[p,..,r] Tuloste: Palautusindeksin paikalla on alkion A[r] arvo ja sen vasemmalla puolella samankokoisia tai pienempiä arvoja ja vastaavasti oikealla puolella samankokoisia tai suurempia. PARTITION(A,p,r) 1. x = A[r] 2. i = p - 1 3. for j = p to r 1 4. if A[j] <= x 5. i = i + 1 6. vaihda A[i] A[j] 7. vaihda A[i + 1] A[r] 8. return i + 1 811312A TRA, Lajittelualgoritmeista 6
III.2.2 Pikalajittelun oikeellisuus Päättyminen varmaa, koska indeksit pienenevät rekursiossa Tutkitaan graafisesti: QUICKSORT: s > s PARTITION Sarana < s s QUICKSORT QUICKSORT Lajittelu toimii, jos PARTITION toimii oikein 811312A TRA, Lajittelualgoritmeista 7
III.2.2 Pikalajittelun oikeellisuus (2) Algoritmin PARTITION oikeellisuus seuraa alla olevasta kolmeosaisesta silmukkainvariantista: Rivien 3-6 silmukan jokaisen kierroksen alussa ehdot 1-3 ovat voimassa jokaiselle taulukon indeksille k 1. jos p <= k <= i, niin A[k] <= x 2. jos i+1 <= k <= j-1, niin A[k] > x 3. jos k = r, niin A[k] = x. 811312A TRA, Lajittelualgoritmeista 8
III.2.3 Pikalajittelun suorituskyky Taulukon koko n PARTITION lineaariaikainen, ts. jos ositetaan taulukon osa, jonka pituus k, niin suoritusaika c k, missä c vakio Pikalajittelun huonoin tapaus: sarana-alkio aina taulukon viimeisenä -> suoritusaika luokkaa 2 c n c (n -1)... 2 1 c n (n -1) (n ) Pikalajittelun paras tapaus: rekursioyhtälö T(n) 2 T(n/2) c n Master Theorem: T(n) (n lg(n)) Voidaan osoittaa että myös keskimääräinen tapaus luokkaa (n lg(n)) Analyysi verrattain mutkikas 811312A TRA, Lajittelualgoritmeista 9
III.3 Kekolajittelu Keksijä J. W. J. Williams (Ks. Williams: Algorithm 232 (HEAPSORT). Communications of the ACM, 7(6):347-348, 1964) Perustuu keko-tietorakenteen muokkaukseen ja ylläpitoon Nopea algoritmi Lajittelee paikallaan 811312A TRA, Lajittelualgoritmeista 10
III.3.1 Binääripuut Binääripuun määritelmä (rekursiivinen): Binääripuu 1. on tyhjä tai 2. koostuu yhdestä juurisolmusta, jolla on lapsinaan kaksi binääripuuta: näitä sanotaan vasemmaksi ja oikeaksi alipuuksi Binääripuussa jokaisella solmulla on siis enintään kaksi lapsisolmua Lehtisolmu: Solmu, jolla ei ole lapsisolmuja 811312A TRA, Lajittelualgoritmeista 11
III.3.1 Binääripuut (2) Binääripuu on lähes täydellinen, jos sen alimman tason lehtisolmut täyttävät solmujen paikkoja peräkkäin vasemmalta lähtien ja ylemmät tasot ovat täynnä. Esimerkki: lähes täydellinen binääripuu 11 8 15 5 9 12 811312A TRA, Lajittelualgoritmeista 12
III.3.1 Binääripuut (3) Lähes täydellisen n-solmuisen binääripuun solmut voidaan asettaa yksikäsitteisesti vastaamaan taulukon A[1,2,,n] alkioita. Solmun A[i] vasen lapsi paikassa 2i ja oikea paikassa 2i+1, esim. 11 8 15 11 8 15 5 9 12 5 9 12 Vasen lapsi Oikea lapsi 811312A TRA, Lajittelualgoritmeista 13
III.3.1 Binääripuut (4) Binääripuun korkeus h on puun pisimmän lehtisolmusta juurisolmuun johtavan reitin sivujen lukumäärä Lähes täydellisen binääripuun solmujen lukumäärä, kun sen korkeus on h: tasolla 1 1 (=2 1-1 ) tasolla 2 2 (=2 2-1 ) tasolla h 2 h-1 tasolla h+1 1.. 2 h Siis kaikkiaan solmujen määrälle n: 2 h n < 2 h+1 Edellisestä h lg(n) < h+1 811312A TRA, Lajittelualgoritmeista 14
III.3.2 Maksimikeko Binääripuu on maksimipuu (minimipuu), jos jokaisella isäsolmulla on suurempi arvo (pienempi) kuin sen lapsisolmuilla Lähes täydellinen binääripuu on maksimikeko (minimikeko), jos se on maksimipuu (minimipuu) Kekolajittelussa käytetään maksimi- tai minimikeon esittämistä ja sen operoimista taulukossa Maksimikeosta helppo poistaa suurin, minimikeosta pienin alkio ja palauttaa nopeasti kekojärjestys Kekoon lisääminen nopeaa Tästä eteenpäin keko tarkoittaa maksimikekoa 811312A TRA, Lajittelualgoritmeista 15
III.3.3 Kekolajittelualgoritmi Syöte: Taulukko A[1,,n] (n=a.length) Tuloste: Taulukko A järjestyksessä HEAPSORT(A) 1. BUILD_MAX_HEAP(A) 2. for i = A.length downto 2 3. vaihda A[1] A[i] 4. A.heap_size = A.heap_size 1 5. MAX_HEAPIFY(A, 1) BUILD_MAX_HEAP(A) Tuloste: Taulukosta A maksimikeko 1. A.heap_size = A.length 2. for i = A.length/2 downto 1 3. MAX_HEAPIFY(A, i) 16
III.3.3 Kekolajittelualgoritmi (2) Syöte: Taulukko A[1,..,n], indeksi i. Tuloste: Puu, jonka juuri A[i] kekojärjestyksessä jos sen vasen ja oikea alipuu kekojärjestyksessä MAX_HEAPIFY(A, i) 1. lft = LEFT(i) ( = 2*i) 2. rgt = RIGHT(i) ( = 2*i+1) 3. if lft <= A.heap_size and A[lft] > A[i] 4. largest = lft 5. else 6. largest = i 7. if rgt <= A.heap_size and A[rgt] > A[largest] 8. largest = rgt 9. if largest!= i 10. vaihda A[i] A[largest] 11. MAX_HEAPIFY(A, largest) 17
III.3.4 Kekolajittelun oikeellisuus: MAX_HEAPIFY Päättyminen: Algoritmia kutsutaan rekursiivisesti vain indeksiä i suuremmilla arvoilla -> indeksi kasvaa ja päättää suorituksen Oletetaan, että A[i] pienempi kuin jokin sen lapsista, mutta vasen ja oikea alipuu maksimikekoja A[i] vaihdetaan suuremman lapsen kanssa (A[largest]) -> Juuri kunnossa, indeksistä largest alkava puu voi olla rikki. Kutsutaan MAX_HEPIFY(A, largest) jne -> Kunnossa viimeistään kun päädytään lehteen Siis MAX_HEAPIFY korrekti 811312A TRA, Lajittelualgoritmeista 18
III.3.4 Kekolajittelun oikeellisuus: BUILD_MAX_HEAP Päättyminen selvää koska MAX_HEAPIFY päättyy jokaisella indeksin arvolla Muu oikeellisuus seuraa silmukkainvariantista: for-silmukan jokaisen kierroksen alussa jokainen indeksien (i+1) ja n välillä oleva solmu on maksimikeon juurisolmu 811312A TRA, Lajittelualgoritmeista 19
III.3.4 Kekolajittelun oikeellisuus: HEAP_SORT Päättyy, koska BUILD_MAX_HEAP ja MAX_HEAPIFY päättyvät Oikeellisuuden osoittava invariantti: for-silmukan jokaisen suorituskerran alussa alitaulukko A[1..i] on maksimikeko, joka sisältää taulukon i pienintä alkiota. Alitaulukko A[(i + 1)..n] puolestaan sisältää taulukon (n - i) suurinta alkiota lajitellussa järjestyksessä. 811312A TRA, Lajittelualgoritmeista 20
III.3.4 Kekolajittelun suorituskyky Mitataan suoritusaikaa suhteessa keon alkioiden lukumäärään n Tällöin keon korkeudelle h: h lg(n) < h+1 MAX_HEAPIFY: Jokainen yksittäinen kutsu vakioaikainen. Rekursiossa edetään aina keossa alemmalle tasolle -> Kompleksisuusluokka O(h) = O(lg(n)) BUILD_MAX_HEAP: Korkeintaan n kappaletta MAX_HEAPIFY-kutsuja -> luokkaa O(nlg(n)) Itse asiassa voidaan osoittaa, että O(n) HEAP_SORT: BUILD_MAX_HEAP ja korkeintaan n kappaletta MAX_HEAPIFY-kutsuja -> luokkaa O(nlg(n)) 811312A TRA, Lajittelualgoritmeista 21
III.3.5 Prioriteettijono (priority queue) Tietorakenne, jossa alkiojoukko S, jonka jokaisella alkiolla on oma tietty prioriteetti (key) Jonosta voidaan aina saada korkeimman prioriteetin alkio ja lisätä uusia alkioita tehokkaasti Voidaan toteuttaa keon avulla Maksimikeko -> maksimiprioriteettijono (max-priority queue) ja minimikeko -> minimiprioriteettijono (minpriority queue) 811312A TRA, Lajittelualgoritmeista 22
III.3.5.1 Maksimiprioriteettijonon operaatiot INSERT(S, x) Lisää alkion x joukkoon S MAXIMUM(S) Palauttaa joukon S prioriteetiltaan suurimman alkion EXTRACT_MAX(S) Palauttaa joukon S prioriteetiltaan suurimman alkion ja poistaa sen INCREASE_KEY(S, x, k) Päivittää alkion x prioriteetin uuteen arvoon k, jonka oletetaan olevan vähintään yhtä suuri kuin alkion x nykyinen avainarvo 811312A TRA, Lajittelualgoritmeista 23
III.3.5.1 Maksimiprioriteettijonon operaatiot (2) HEAP_MAXIMUM(A) 1. return A[1] HEAP_EXTRACT_MAX(A) 1. if A.heap_size < 1 2. error underflow 3. max = A[1] 4. A[1] = A[A.heap_size] 5. A.heap_size = A.heap_size - 1 6. MAX_HEAPIFY(A, 1) 7. return max 811312A TRA, Lajittelualgoritmeista 24
III.3.5.1 Maksimiprioriteettijonon operaatiot (3) PARENT(i) 1. return j/2 HEAP_INCREASE_KEY(A, i, key) 1. if key < A[i] 2. error avain liian pieni 3. A[i] = key 4. while i > 1 and A[PARENT(i)] < A[i] 5. vaihda A[i] A[PARENT(i)] 6. i = PARENT(i) 811312A TRA, Lajittelualgoritmeista 25
III.3.5.1 Maksimiprioriteettijonon operaatiot (4) HEAP_INSERT(A, key) 1 A.heap_size = A.heap_size + 1 2 A[A.heap_size] = - 3 HEAP_INCREASE_KEY(A, A.heap_size, key) 811312A TRA, Lajittelualgoritmeista 26
III.4. Lajittelualgoritmien suorituskyvyn rajoista Lomituslajittelua, pikalajittelua ja kekolajittelua pidetään nopeina algoritmeina Onko syytä? Lajittelu voi perustua muuhunkin kuin alkioiden vertailuun Esimerkiksi tunnetaan alkioiden ylä- ja alaraja -> voidaan tehdä laskentalajittelu Tarkastellaan vertailuun perustuvia algoritmeja 811312A TRA, Lajittelualgoritmeista 27
III.4.1 Vertailuun perustuva lajittelu Voidaan esittää binääripuuna, jossa solmut vastaavat vertailuja Algoritmin päätöspuu Polku juuresta lehteen kuvaa tehtyjä vertailuja Lehti kertoo mihin järjestykseen suoritetuilla vertailuilla ja niiden tuloksilla päädytään 811312A TRA, Lajittelualgoritmeista 28
a 1? a 2 > a 2? a 3 a 1? a 3 > > < a 1, a 2, a 3 > a 1? a 3 < a 2, a 1, a 3 > a 2? a 3 > > < a 1, a 3, a 2 > <a 3, a 1, a 2 > < a 2, a 3, a 1 > <a 3, a 2, a 1 > Kolmen alkion (a 1,a 2,a 3 ) lajittelualgoritmin päätöspuu. Kolme alkiota voivat olla 6 eri järjestyksessä -> Puussa oltava vähintään 6 lehteä.
III.4.1 Vertailuun perustuva lajittelu (2) Päätöspuun syvyys S -> on olemassa syöte, jolle on tehtävä S vertailua Syvyys S -> puussa lehtiä korkeintaan 2 S Jos n alkiota järjestettävänä, ne voivat olla n! eri järjestyksessä ja jokaista järjestystä kohti on oltava lehti. Siis n! 2 S Arvioimalla saadaan S ( 1/ 2) nlg n ( n/ 2) ( n lg n) Seuraus: vertailuun perustuva lajittelualgoritmi ei voi olla nopeampi kuin luokkaa ( n lg n) 811312A TRA, Lajittelualgoritmeista 30
III.4.2 Lineaariaikainen lajittelu: Laskentalajittelu Syöte: Taulukko A[1,..,n], n >= 1, luku k >= max(a) Tulostus: Taulukko B[1,..,n], jossa A:n alkiot suuruusjärjestyksessä LASKENTALAJITTELU(A,k) 1. varaa taulukko B[1,..,n] 2. varaa taulukko C[0,..k] // Väliaikainen // työtaulukko 3. for i=0 to k 4. C[i] = 0 5. for j=1 to length(a) 6. C[A[j]] = C[A[j]]+1 7. for i=1 to k 8. C[i] = C[i]+C[i-1] 9. for j = length(a) downto 1 10. B[C[A[j]]] = A[j] 11. C[A[j]] = C[A[j]]-1 12. return B
III.4.2 Lineaariaikainen lajittelu: Laskentalajittelu (2) Algoritmi toimii lineaarisessa ajassa Kompleksisuusluokka ( n k) Ei siis voi perustua (pelkästään) vertailuihin Perustuu siihen, että taulukon alkiot kokonaislukuja väliltä [0,k] On olemassa myös muita lineaariajassa toimivia lajittelualgoritmeja 811312A TRA, Lajittelualgoritmeista 32