Tietorakenteet ja algoritmit Algoritmianalyysin perusteet Ari Korhonen 1
5. ALGORITMIANALYYSI 5.1 Johdanto 5.2 Tavoitteet 5.3 Algoritmien luokittelu 5.4 Kertaluokkamerkinnät (Big Oh Notation) 5.5 Kertaluokkamerkinnöillä laskeminen 5.6 Muita tunnuslukuja 5.7 Iteratiivisen ohjelman kompleksisuus 5.8 Rekursiiviset ohjelmat 5.9 Rekursioyhtälöt 5.10 Kuinka analyysi tarkistetaan? 5.11 Analyyttisten tulosten tulkinta 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 2
5.1 Johdanto MIKSI tarvitaan algoritmianalyysiä? Ohjelman resurssitarpeiden ennustaminen CPU-aika muistitila Algoritmien keskinäinen vertailu Sopivan algoritmin valitseminen (perusteet) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 3
MITEN algoritmeja voi analysoida? 1. Empiirinen mittaaminen ja ekstrapolointi Tulos riippuu syöteaineistosta Tulos riippuu toteutuksesta Ekstrapolointi voi johtaa vääriin päätelmiin 2. Matemaattinen analyysi Luotettavampi, mutta ei ongelmaton Tulokset voivat olla epäkäytännöllisiä Voi johtaa analyyttisesti vaikeisiin ongelmiin 3. Käsitteellinen luokittelu Kvalitatiivinen (luokitteleva, kuvaileva) analyysi harvoin riittävä 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 4
5.2 Algoritmianalyysin tavoitteet A) Syöteaineiston laatu ei saa johtaa vääriin tuloksiin Koska täsmällinen ennustaminen suoritusajasta ei ole mahdollista, haetaan seuraavia tunnuslukuja: Pahin tapaus (worst case performance) Realistinen tai sitten ei Esim. haetaan tiettyä alkiota linkitetystä listasta. Mikä on pahin tapaus? Keskimääräinen tapaus (average case performance) Usein merkittävämpi tulos Analyysi usein vaikeaa Esim. Mikä on keskimääräinen tekstitiedosto? 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 5
Tavoitteet... B) Erotetaan algoritmi ja sen toteutus toisistaan Toteutus vaikuttaa suoritusaikaan vain kertoimen kautta C) Etsitään pienintä ylärajaa Mahdollisimman lähellä teoreettista ylärajaa D) Keskitytään olennaiseen Pääosa CPU-ajasta kuluu vain pienessä osassa ohjelmaa E) Täsmällinen lauseke harvoin tarpeen Määräävä termi riittää (esim. N 2 + N N 2, kun N >> 1) Syötteen tai aineiston koon eli alkioiden lukumäärän funktio, merkitään T(N) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 6
5.3 Algoritmien luokittelu, T(N) = f(n), jossa f(n) = 1 : kiinteä (vakio) suoritusaika esim. lausekkeen evaluointi N 2 : neliöllinen esim. sijoituslajittelu log N : logaritminen esim. puolitushaku N 3 : kuutiollinen esim. matriisitulo N : lineaarinen esim. lineaarinen haku N*log N : "N log N" esim. Mergesort 2 N : eksponentiaalinen esim. salasanan haku, travelling salesman Eksponentiaaliset algoritmit eivät sovellu suurille aineistoille, mutta niitä esiintyy monien käytännön ongelmien perusratkaisuissa 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 7
Esim. Tarkastellaan neljää eri algoritmia, joiden tehokkuusluvut ovat 100N, 5N 2, N 3 /2 ja 2 N Oletetaan koneet, joista toinen laskee 10 6 askelta sekunnissa, toinen 10 7 askelta sekunnissa algoritmi N (10 6 s) N (10 7 s) muutos 100N 10 100 10,0 5N 2 14 45 3,2 N 3 /2 12 27 2,3 2 N 10 13 1,3 Eksponentiaalisella algoritmilla konetehon kymmenkertaistuminen johtaa siihen, että pystytään käsittelemään vain 30v% suurempaa ongelmaa! 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 8
5.4 Kertaluokkamerkinnät Funktio T(N) O( f(n) ), jos on olemassa c ja N 0 siten, että T(N) < c f(n), kaikille N > N 0 Merkitään: T(N) = O( f(n) ) Tämä on syötteestä ja toteutuksesta riippumaton yläraja laskentaan kuluva aika c f(n) T(n) f(n) ongelman koko HUOM! N 0 Kuvaa askelten määrää, EI kulutettuja CPU-sekunteja Yläraja voi olla turhan epätarkka eli epärealistinen c ja N 0 eivät ole välttämättä pieniä Funktiot asymptoottisesti kasvavia (vrt. suoritusaika) Asymptoottinen käyttäytyminen ei välttämättä ratkaise "pienillä" N:n arvoilla, esim. 10N 2 < 1000*N, N < 100 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 9
Osoita, että n 2 + n 1 = O(n 2 ) Etsitään (mitkä tahansa) c ja N 0 s.e. n 2 + n 1 < cn 2, kun n > N 0 Voidaan valita esim. c = 2, jolloin epäyhtälö on voimassa, kun n > 0, joten valitaan N 0 = 0, jolloin saadaan n 2 + n 1 < 2n 2, kun n > 0 Eli n 2 + n 1 = O(n 2 ) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 10
Lähde: http://science.slc.edu/~jmarshall/courses/2002/spring/cs50/bigo/index.html 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 11
5.5 Kertaluokkamerkinnöillä laskeminen 1. f(x) = O(f(x)) 2. f(x) = O(x * f(x)) 3. c * f(x) = O(f(x)) 4. f(x) + c = O(f(x)) 5. f(x) + g(x) = O(MAX[ f(x), g(x) ]) = MAX[ O(f(x)), O(g(x)) ] 6. f(x) * g(x) = O(f(x) * g(x)) N 7. a i *x i = O(x N ) i=0 8. log 2 x = O(log 10 x) Luentotehtävä: - pareittain - selitä, perustele, todista 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 12
log k x = O(log p x), k ja p vakioita Todistus: log k x = log p x / log p k = (1/vakio) * log p x = O(log p x) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 13
VIRHEITÄ: 1. O(f(x)) - O(f(x)) = 0 (p.o. O(f(x)) ) 2. f(x) = O(g(x) / 2) 3. f(x) = O(x 2 + x) 4. O(f(x)) = f(x) 5. f(x) <= O(g(x)) 6. f(x) >= O(g(x)) OK: f(x, M) = O(g(x) + M) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 14
5.6 Muita tunnuslukuja Iso-O (Big-Oh): f on T:lle yläraja T(N) = O( f(n) ), jos on olemassa c ja N 0 siten, että T(N) < cf(n) kaikille N > N 0 Iso-Omega: f on T:lle alaraja T(N) = Ω( f(n) ), jos on olemassa c ja N 0 siten, että T(N) > cf(n) kaikille N > N 0 Iso-Theta: f kasvaa täsmälleen kuin T T(N) = Θ( f(n) ) T(N) = O( f(n) ) ja T(N) = Ω( f(n) ) Pikku-o (Little-oh): f on T:n aito yläraja T(N) = o( f(n) ) T(N) = O( f(n) ) ja T(N) Θ( f(n) ) Huom! Nyt ei puhuta ylärajoista tavallisessa mielessä 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 15
t c 3 N cn 3 c 0 N 2 T(N) = 77+N/2 K3.3 c 2 sqrt(n) N T(N) = O(N 2 ) T(N) = O(N 3 ) T(N) = O(N) T(N) = Ω(sqrt(N)) T(N) = Ω(N) T(N) = θ(n) T(N) = o(n 2 ) T(N) = o(n 3 ) Big-Oh on tärkein tunnusluku. 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 16
5.7 Iteratiivisen ohjelman O-kompleksisuus Peräkkäiset lauseet s=0; vakio O(1) for (i=0; i<n; i++) O(N) s= s+1; Valitaan maksimi O(N) Haarautuminen (if-then-else; switch; case) Valitaan maksimi Silmukat (for; while; do...while; repeat...until) for (i=1; i<n; i++) for (j=i+1; j<=n; j++) s= s+1; (N-1)*N/2 = O(N 2 ) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 17
5.8 Rekursiiviset ohjelmat int fibonacci(int n) { if (n<=1) return 1; else return fibonacci(n-1) + fibonacci(n-2); } F3 F6 F5 F4 F4 F3 F3 F2 F2 F1 F2 F1 F2 F1 F0 T(0) = T(1) = 1 F2 F1 F1 F0 F1 F0 F1 F0 T(N) = T(N-1) + T(N-2) + 2 >= fib(n) (3/2) N <= fib(n) <= (5/3) N T(N) on eksponentiaalinen F1 F0 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 18
Rekursiivinen kertoma-funktio int factorial(int n) { if (n==0) return 1; else return n*factorial(n-1); } T(0) = 1 T(N) = T(N-1) + 1 T(N) = O(N) Iso O -notaatiossa yhtä hyvä kuin iteratiivinen Rekursiosta aiheutuu yleiskustannuksia 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 19
5.9 Rekursioyhtälöt Mentaalisen mallin muodostuminen (muna-kana-ongelma) 1. Rekursiohistoriapuut, laskennan etenemisen sisäistäminen 2. Laskennan vaativuuden erottaminen itse laskennen lopputuloksesta 3. Valikoitu arvaus laskennan vaativuudelle 4. Yhteys induktiotodistukseen 5. Rekursioyhtälö mentaalisen mallin ulkoistamisen välineenä Rekursioyhtälöiden ratkaisumenetelmiä (todistus) Aritmeettiset ja geometriset sarjakehitelmät Parametrien muunnokset Lausekkeen manipulointi Näiden yhdistely Master Theorem (Cormen) Induktiotodistus (e-book) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 20
Esim 1. Linkitetyn listan läpikäynti silmukassa, poista joka kierroksella yksi alkio (ks. aritmeettinen sarja): T(N) = T(N-1) + N, T(1) =1 N T(N) = k = N (N + 1) / 2 k=1 T(N) on noin N 2 / 2 = O(N 2 ) T(N-1) = T((N-1)-1) + (N-1) = T(N-2) + N - 1 T(N-2) = T((N-2)-1) + (N-2) = T(N-3) + N - 2 T(N-k) = T((N-k)-1) + (N-k) = T(N-k-1) + N - k 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 21
Esim 2. Binäärihaku, puolita aineisto vakioajassa: T(N) = T(N/2) + 1, T(1) =1 N = 2 k, k = log 2 N (parametrin muunnos) T(2 k ) = T(2 k-1 ) + 1 = T(2 k-2 ) + 1 + 1 = T(2 0 ) + k = k +1 T(N) = O(k) = O(log N) Esim 3. Quick select, puolita aineisto lineaarisessa ajassa (geometrinen sarja): T(N) = T(N/2) + N, T(1) = 1 T(N) = N + N/2 + N/4 + N/8 +... = 2N = O(N) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 22
Esim 4. Hajoita ja hallitse : Jaa aineisto kahteen osaan lineaarisessa ajassa, käsittele molemmat puolet rekursiivisesti T(N) = 2T(N/2) + N, T(1) = 1 N = 2 k, k = log 2 N T(2 k ) = 2T(2 k-1 ) + 2 k <=> T(2 k ) / 2 k = T(2 k-1 ) / 2 k-1 + 1 <=> T(2 k-1 ) / 2 k-1 = T(2 k-2 ) / 2 k-2 + 1 <=> T(2 k-2 ) / 2 k-2 = T(2 k-3 ) / 2 k-3 + 1... <=> T(2 2 ) / 2 2 = T(2 1 ) / 2 1 + 1 <=> T(2 1 ) / 2 1 = T(2 0 ) / 2 0 + 1 Lasketaan yhteen (teleskooppi) T(2 k ) / 2 k = k T(N) = T(2 k ) = k 2 k = N log N = O(N log N) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 23
Esim 5. Potenssiinkorotus: Jos laskettaisiin x n = x*x*x*...*x, n-1 kertolaskua => O(n) Mutta voidaan laskea esim. x 9 = (x 2 ) 4 x = ((x 2 ) 2 ) 2 x (vain 4 kertolaskua 8:n sijaan!) integer pow(int x, int n){ switch (n) { case 0: return 1; break; case 1: return x; break; default: if (n&1) return pow(x*x, n/2)*x; else return pow(x*x, n/2); } } T(n) = T(n/2) + 1, T(1) = T(0) = 1 T(n) = O(log n) (Ratkaisu: vrt. Esim. kohta 2 edellä) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 24
5.10 Kuinka analyysi tarkistetaan? Empiirisesti Toteuttamalla ohjelma Tehdään koeajoja mahdollisimman suurilla aineistoilla N, 2N, 4N, 8N,... Kun N tuplaantuu O(N) - algoritmien ajoaika tuplaantuu O(N 2 ) : nelinkertaistuu O(N 3 ) : kahdeksankertaistuu jne. O(log N) : vain vakiotermi lisää riippumatta N:stä O(N log N) : hiukan huonompi kuin O(N) Alemman asteen termit sotkevat empiiristä tarkastelua 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 25
Jos T(N) on mitattu suoritusaika ja oletetaan, että T(N) = O( f(n) ), niin voidaan tilastoida suuretta c = T(N)/f(N) satunnaisilla N:n arvoilla Jos c lähestyy positiivista arvoa f(n) on tiukka raja, ehkä T(N) = θ( f(n) ) Jos c lähestyy nollaa f(n) on liian lepsu raja, voidaan sanoa että T(N) = o( f(n) ) Jos arvot hajaantuvat f(n) kasvaa liian hitaasti, T(N) ei ole O( f(n) ) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 26
5.11 Analyyttisten tulosten tulkinta Usein ei ole olemassa selvästi parasta algoritmia tai tietorakennetta. Valintaan vaikuttaa monia tekijöitä : kuinka usein ohjelmaa tarvitaan? syötteen koko (aineiston määrä) suoritusaikavaatimukset reaaliaikainen / eräluonteinen työ lisäysten / poistojen / päivitysten määrä ja suhde hakuihin Matemaattinen analyysi kertoo vain osan totuudesta. Muita tekijöitä ovat : kääntäjä käyttöjärjestelmä I/O:n määrä Yleensä kannattaa aloittaa yksinkertaisella menetelmällä (brute force well tuned) 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 27
Ongelman kasvaessa algoritmia voidaan vaihtaa tehokkaampaan uusimatta koko ohjelmaa N 2 N * LOG N Algoritmin viilaaminen katkaistaan sopivasti. Ohjelmakoodin optimointi käsin kannattaa harvoin. Tärkeämpää on se, että ohjelmassa on varauduttu muutoksiin hyvin ehjä kokonaisuus abstraktit tietotyypit Ohjelman ylläpidettävyys on usein tärkeämpää kuin tehokkuus! 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 28
Ensi kerraksi Tee viikkojen 38-39 viikkoharjoitukset Viikon 39 viikkoharjoitusten aiheena on prioriteettijonot, joka aihepiirinä on jätetty itseopiskelun varaan. Tutustu algoritmien suunnittelumenetelmiin Hajoita ja hallitse Taulukointi (dynaaminen ohjelmointi) Ks. luentotehtävä (viikko 39) A+:ssa 17.9.2015 Tietorakenteet ja algoritmit - syksy 2015 29