Lähteet. OHJ-2010 TIETORAKENTEIDEN KÄYTTÖ lukuvuosi 2012-2013 Terhi Kilamo



Samankaltaiset tiedostot
4 Tehokkuus ja algoritmien suunnittelu

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

TIE Tietorakenteet ja algoritmit 25

1 Erilaisia tapoja järjestää

5 Kertaluokkamerkinnät

Tietorakenteet ja algoritmit - syksy

Algoritmit 1. Luento 2 Ke Timo Männikkö

f(n) = Ω(g(n)) jos ja vain jos g(n) = O(f(n))

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Algoritmit 1. Luento 3 Ti Timo Männikkö

Algoritmit 2. Luento 1 Ti Timo Männikkö

9 Erilaisia tapoja järjestää

811312A Tietorakenteet ja algoritmit I Johdanto

Algoritmit 1. Luento 1 Ti Timo Männikkö

Algoritmit 2. Luento 2 To Timo Männikkö

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

1 Puu, Keko ja Prioriteettijono

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 2. Luento 8 To Timo Männikkö

Algoritmit 1. Luento 11 Ti Timo Männikkö

811120P Diskreetit rakenteet

Algoritmit 2. Luento 14 Ke Timo Männikkö

811120P Diskreetit rakenteet

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Algoritmit 1. Luento 10 Ke Timo Männikkö

Algoritmit 1. Luento 10 Ke Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

811312A Tietorakenteet ja algoritmit , Harjoitus 2 ratkaisu

811312A Tietorakenteet ja algoritmit, , Harjoitus 3, Ratkaisu

Tiraka, yhteenveto tenttiinlukua varten

1.1 Tavallinen binäärihakupuu

A TIETORAKENTEET JA ALGORITMIT

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

Algoritmit 2. Luento 13 Ti Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Ohjelmoinnin perusteet Y Python

(p j b (i, j) + p i b (j, i)) (p j b (i, j) + p i (1 b (i, j)) p i. tähän. Palaamme sanakirjaongelmaan vielä tasoitetun analyysin yhteydessä.

Algoritmit 1. Demot Timo Männikkö

1.4 Funktioiden kertaluokat

Algoritmit 1. Demot Timo Männikkö

Algoritmit 1. Luento 12 Ti Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, , vastauksia

Diskreetin matematiikan perusteet Laskuharjoitus 2 / vko 9

Algoritmit 2. Luento 7 Ti Timo Männikkö

Algoritmit 1. Luento 14 Ke Timo Männikkö

9.3 Algoritmin valinta

Algoritmit 2. Demot Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

Algoritmit 1. Luento 12 Ke Timo Männikkö

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

Pikalajittelu: valitaan ns. pivot-alkio esim. pivot = oikeanpuoleisin

TAMPEREEN TEKNILLINEN YLIOPISTO

Algoritmit 2. Luento 6 To Timo Männikkö

TKT20001 Tietorakenteet ja algoritmit Erilliskoe , malliratkaisut (Jyrki Kivinen)

AVL-puut. eräs tapa tasapainottaa binäärihakupuu siten, että korkeus on O(log n) kun puussa on n avainta

Algoritmit 1. Luento 4 Ke Timo Männikkö

A TIETORAKENTEET JA ALGORITMIT

Tietorakenteet ja algoritmit

3. Laskennan vaativuusteoriaa

Tarkennamme geneeristä painamiskorotusalgoritmia

Zeon PDF Driver Trial

Luku 8. Aluekyselyt. 8.1 Summataulukko

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

58131 Tietorakenteet (kevät 2009) Harjoitus 9, ratkaisuja (Antti Laaksonen)

ja λ 2 = 2x 1r 0 x 2 + 2x 1r 0 x 2

Algoritmit 1. Luento 6 Ke Timo Männikkö

58131 Tietorakenteet (kevät 2009) Harjoitus 6, ratkaisuja (Antti Laaksonen)

Tämä on helpompi ymmärtää, kun tulkitaan keko täydellisesti tasapainotetuksi binääripuuksi, jonka juuri on talletettu taulukon paikkaan

Algoritmit 1. Demot Timo Männikkö

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

Algoritmit 1. Luento 5 Ti Timo Männikkö

A TIETORAKENTEET JA ALGORITMIT

Algoritmien suunnittelu ja analyysi (kevät 2004) 1. välikoe, ratkaisuja

Ohjelmoinnin perusteet Y Python

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Tietorakenteet, laskuharjoitus 2,

Tietorakenteet, laskuharjoitus 7, ratkaisuja

Johnson, A Theoretician's Guide to the Experimental Analysis of Algorithms.

Ohjelmoinnin perusteet Y Python

Nopea kertolasku, Karatsuban algoritmi

Algoritmit 2. Luento 6 Ke Timo Männikkö

useampi ns. avain (tai vertailuavain) esim. opiskelijaa kuvaavassa alkiossa vaikkapa opintopistemäärä tai opiskelijanumero

Ohjelmoinnin perusteet Y Python

58131 Tietorakenteet ja algoritmit (kevät 2013) Kurssikoe 2, , vastauksia

Ohjelmoinnin perusteet Y Python

811312A Tietorakenteet ja algoritmit III Lajittelualgoritmeista

TAMPEREEN TEKNILLINEN YLIOPISTO

Algoritmi on periaatteellisella tasolla seuraava:

Ohjelmoinnin perusteet Y Python

ITKP102 Ohjelmointi 1 (6 op)

811312A Tietorakenteet ja algoritmit, VI Algoritmien suunnitteluparadigmoja

58131 Tietorakenteet ja algoritmit (syksy 2015) Toinen välikoe, malliratkaisut

Tutkimusmenetelmät-kurssi, s-2004

58131 Tietorakenteet ja algoritmit (syksy 2015)

7.4 Sormenjälkitekniikka

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

Transkriptio:

OHJ-2010 Tietorakenteiden käyttö 1 OHJ-2010 TIETORAKENTEIDEN KÄYTTÖ lukuvuosi 2012-2013 Terhi Kilamo OHJ-2010 Tietorakenteiden käyttö 2 Lähteet Luentomoniste pohjautuu vahvasti Antti Valmarin luentomonisteeseen Tietorakenteet ja algoritmit. Useimmat algoritmit ovat peräisin kirjasta Introduction to Algorithms; Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. Lisäksi luentomonistetta koottaessa on käytetty seuraavia kirjoja: Introduction to The Design & Analysis of Algorithms; Anany Levitin Olioiden ohjelmointi C++:lla; Matti Rintala, Jyke Jokinen Tietorakenteet ja Algoritmit; Ilkka Kokkarinen, Kirsti Ala-Mutka The C++ Standard Library; Nicolai M. Josuttis OHJ-2010 Tietorakenteiden käyttö 3 OHJ-2010 Tietorakenteiden käyttö 4 Sisältö Kurssin käytännönjärjestelyt 2012 9 Tavoitteet............................................. 10 Kurssin suorittaminen...................................... 11 Harjoitukset............................................ 12 Harjoitustyöt............................................ 13 bythemark............................................ 14 Arvostelu............................................. 15 Kurssin henkilökunta....................................... 16 Tärkeimmät tiedotuskanavat................................. 17 Materiaali............................................. 18 Johdanto 19 Miksi?................................................ 20 Käsitteitä ja merkintöjä 26 Tavoitteet............................................. 27 Peruskäsitteistöä......................................... 28 INSERTION-SORT.......................................... 34 Algoritmien toteutuksesta................................... 36 Tehokkuus ja algoritmien suunnittelu 42 Kertaluokat............................................ 43 Pala kerrallaan.......................................... 51 Hajoita ja hallitse......................................... 54 MERGE-SORT............................................ 57 MERGE............................................... 59 Kertaluokkamerkinnät...................................... 66 Θ-merkintä............................................ 67 O-merkintä............................................ 70 Ω-merkintä............................................ 72 Merkintöjen keskinäiset suhteet................................ 73 Suorituskykykäsitteitä...................................... 78 Ajoajan mittayksiköt....................................... 79 Muistin käytön mittayksiköt................................... 80 Algoritmin valinta........................................ 82 BIN-SEARCH............................................ 87 Järjestämisalgoritmit 90 Järjestäminen keon avulla................................... 91 Binääripuut............................................ 91 Keko................................................ 93 HEAPIFY............................................... 97 BUILD-HEAP............................................ 98 Taulukon järjestäminen keon avulla.............................. 100 HEAPSORT............................................. 100 Prioriteettijono.......................................... 105 HEAP-MAXIMUM.......................................... 107 HEAP-EXTRACT-MAX........................................ 108 HEAP-INSERT............................................ 109 QUICKSORT............................................. 110 PARTITION.............................................. 112 Satunnaistaminen........................................ 120 RANDOMIZED-PARTITION..................................... 122 RANDOMIZED-QUICKSORT..................................... 123 RANDOMIZED-SELECT....................................... 125

OHJ-2010 Tietorakenteiden käyttö 5 Muita järjestämisalgoritmeja.................................. 128 Järjestäminen laskemalla.................................... 128 COUNTING-SORT.......................................... 129 DATE-COMPARE.......................................... 131 BUCKET-SORT............................................ 137 Kuinka nopeasti voi järjestää?................................. 140 Lista- ja taulukkorakenteet 143 Dynaamisen joukon käsite................................... 144 Osoittimet ja listat........................................ 150 LIST-SEARCH............................................ 151 LIST-INSERT............................................. 152 LIST-DELETE............................................. 152 ALLOCATE-OBJECT........................................ 157 FREE-OBJECT............................................ 157 Pino................................................. 158 STACK-EMPTY............................................ 159 PUSH................................................ 159 POP................................................. 159 Pino taulukolla.......................................... 160 STACK-EMPTY............................................ 160 PUSH................................................ 160 POP................................................. 161 jono................................................ 162 QUEUE-EMPTY........................................... 162 ENQUEUE.............................................. 163 DEQUEUE.............................................. 163 Rengaspuskuri.......................................... 164 OHJ-2010 Tietorakenteiden käyttö 6 QUEUE-EMPTY........................................... 164 ENQUEUE.............................................. 165 DEQUEUE.............................................. 165 Hyppylista............................................. 167 Hajautustaulu........................................... 170 CHAINED-HASH-SEARCH..................................... 173 CHAINED-HASH-INSERT...................................... 173 CHAINED-HASH-DELETE...................................... 173 Puurakenteet 181 Tavallinen binäärihakupuu................................... 182 PREORDER-TREE-WALK...................................... 184 INORDER-TREE-WALK....................................... 185 POSTORDER-TREE-WALK...................................... 186 R-TREE-SEARCH.......................................... 187 TREE-SEARCH............................................ 188 TREE-MINIMUM........................................... 189 TREE-MAXIMUM.......................................... 189 TREE-SUCCESSOR......................................... 191 TREE-SCAN-ALL.......................................... 192 TREE-INSERT............................................. 194 TREE-DELETE............................................ 195 Puna-musta binäärihakupuu.................................. 199 LEFT-ROTATE............................................ 203 RB-INSERT............................................. 205 RB-DELETE............................................. 209 RB-DELETE-FIXUP.......................................... 210 B-puut............................................... 211 OHJ-2010 Tietorakenteiden käyttö 7 Merkkijonopuu (trie)....................................... 216 TRIE-SEARCH............................................ 218 TRIE-INSERT............................................. 219 TRIE-DELETE............................................. 220 C++:n standardikirjasto 223 Yleistä C++:n standardikirjastosta............................... 224 Iteraattorit............................................. 227 Säiliöt................................................ 235 Vektori............................................... 238 Pakka............................................... 242 Lista................................................ 243 Joukko ja monijoukko...................................... 244 Kuvaus ja monikuvaus...................................... 246 Bittivektori............................................. 249 Merkkijonot............................................ 249 Pino................................................. 251 Jono................................................ 252 Prioriteettijono.......................................... 252 Geneeriset algoritmit...................................... 255 Puolitushaku........................................... 257 Järjestämisalgoritmit....................................... 258 Ositus (partitiointi)........................................ 259 Keot................................................ 260 Joukko-operaatiot........................................ 261 Graafialgoritmit 267 Graafien esittäminen tietokoneessa............................. 268 Yleistä graafialgoritmeista................................... 274 OHJ-2010 Tietorakenteiden käyttö 8 Leveyteen ensin -haku (breadth-first)............................ 276 BFS................................................. 277 PRINT-PATH............................................. 281 Syvyyteen ensin -haku (depth-first).............................. 282 DFS(s)............................................... 284 DFS(u)............................................... 288 Dijkstran algoritmi........................................ 292 DIJKSTRA.............................................. 295 RELAX................................................ 295 Ahneet algoritmit ja välitulosten tallentaminen 298 Välitulosten säilyttäminen................................... 299 VERY-SLOW-FIBONACCI...................................... 299 MEMOIZED-FIBONACCI...................................... 302 MEM-FIB-RECURS......................................... 302 Dynaamisen ohjelmoinnin periaate............................. 305 DYNAMIC-FIBONACCI....................................... 306 MEMORY-SAVING-FIBONACCI.................................. 312 Ahneet algoritmit........................................ 313 GREEDY-ACTIVITY-SELECTOR................................... 314 MIN-COIN............................................. 319 Mitä tehdä kun tehokasta ratkaisua ei löydy? 320

OHJ-2010 Tietorakenteiden käyttö 9 1 Kurssin käytännönjärjestelyt 2012 Käydään alkuun läpi käytännön asioita kurssin suorittamisesta Tästä luvusta löydät kurssin tavoitteet, luento- ja harjoitusajat ja -paikat, arvosteluperusteet sekä vastuuhenkilöiden yhteystiedot ja tiedot kurssin oppimateriaalista. OHJ-2010 Tietorakenteiden käyttö 10 1.1 Tavoitteet Tavoitteena on kurssin jälkeen tuntea yleisimmin käytössä olevat tietorakenteet sekä joukko algoritmeja niiden kanssa toimimiseen Tavoitteena on myös osata analysoida yksinkertaisen ohjelman tai algoritmin asymptoottista ajankäyttöä ajankäytön esittäminen kertaluokkanotaatioilla ratkaisuun sopivimman tietorakenteen valitseminen käyttää ohjelmointikielten kirjastoja Kurssi olettaa perusohjelmointitaitojen olevan jo aikaisemmilta kursseilta hallussa OHJ-2010 Tietorakenteiden käyttö 11 1.2 Kurssin suorittaminen Kurssin suorittaminen koostuu seuraavista: Luennot (2h/vk) Harjoitukset (2h/vk) Harjoitustyöt (3kpl, pakollisia) bythemark-harjoituksia (60% pisteistä pakollista) Harjoitustyöt keskittyvät kurssin keskeisten asioiden opetteluun käytännössä OHJ-2010 Tietorakenteiden käyttö 12 1.3 Harjoitukset Harjoitukset pidetään viikottain alkaen 3.9.2012. Viikkoharjoituksiin ei tarvitse ilmoittautua ja harjoitusryhmää voi vaihtaa tarpeen mukaan. Viikkoharjoitusten tehtäviin ei julkaista malliratkaisuja. Harjoituksia järjestetään Maanantai 12-14 ja 14-16 (englanniksi) Tiistai 12-14 ja 16-18 Keskiviikko 12-14 Torstai 8-10 ja 14-16 salissa TC128

OHJ-2010 Tietorakenteiden käyttö 13 1.4 Harjoitustyöt Kurssilla on kolme pakollista, henkilökohtaista, harjoitustyötä. Aikaisemmin suoritettuja harjoitustöitä ei hyväksytä. Harjoitustyön deadline on aina mainittuna päivänä klo 24.00. Kaikilla töillä on kaksi deadlinea: pehmeä ja kova. Työ Soft deadline Deadline Algoritmi 21.09.2012 28.09.2012 Tietorakenne 26.10.2012 02.11.2012 Kirjastototeutusten käyttö 30.11.2012 07.12.2012 Deadlineista ei jousteta ilman erityistä syytä (lääkärintodistus tms.) Mikäli hyvin perustellusta syystä tarvitset lisäaikaa, ota yhteyttä assistenttiin reilusti ennen deadlinea. OHJ-2010 Tietorakenteiden käyttö 14 1.5 bythemark bythemark on verkossa tarjottava joukko automaattisesti arvosteltavia algoritmisimulaatiotehtäviä bythemark-tehtäville on annettu aikaa 15.1.2013 saakka ja 60 % pisteistä on suoritettava. Tehtäviä kannattaa tehdä aktiivisesti kurssin edetessä. Siten niistä on eniten hyötyä. OHJ-2010 Tietorakenteiden käyttö 15 1.6 Arvostelu Kurssin arvosana ja arvosanarajat määräytyvät tentistä ja harjoitustöistä saatujen pisteiden perusteella tentin maksimipistemäärä on 30 harjoitustöistä voi saada 6 pistettä maksimipistemäärä on 36 pistettä Lisäksi aktiivisesta osallistumisesta harjoituksiin on tarjolla 3 bonuspistettä, jotka voivat korottaa arvosanaa yhdellä. Bonuspisteillä ei voi korottaa hylättyä arvosanaa. OHJ-2010 Tietorakenteiden käyttö 16 1.7 Kurssin henkilökunta Kurssin vastuuhenkilö: Terhi Kilamo terhi.kilamo@tut.fi työhuone: TF113 työpuhelin: 040 849 0723 Terhi vastaa kurssin sisällöstä, luennoista, materiaalista, arvostelusta ja korvauksista Pääassistentti: Seppo Koivisto seppo.koivisto@tut.fi työhuone: TF109 Seppo vastaa kurssin kaikista käytännönjärjestelyistä Assistentit: Anna-Liisa Mattila, Mikko Airaksinen ja Niko Junkala auttavat Seppoa, pitävät harjoituksia ja korjaavat harjoitustöitä.

OHJ-2010 Tietorakenteiden käyttö 17 1.8 Tärkeimmät tiedotuskanavat Kurssin kotisivultaûûûº ºØÙغ» Ø Ö löydät kurssiin ja sen suorittamiseen liittyvää, kurssin aikana muuttumatonta tietoa. Kotisivujen kautta julkaistaan myös viikkoharjoitustehtävät ja harjoitustöiden tehtävänannot. Ajankohtaisista asioista kurssilla tiedotetaan kurssin uutisryhmässäøùøºóøºø Ö,jota kannattaa seurata Kurssilla on käytössä Idle-kurssihallintajärjestelmä Ð º ºØÙغ,jonka kautta hoidetaan harjoitustöiden palauttaminen ja josta pääsee lukemaan uutisryhmää Kurssin irc-kanava Ø Ö :lla saa vertaistukea ja voi pyytää neuvoa kurssihenkilökunnalta. Kurssia koskeva sähköposti tulee lähettää osoitteeseen tiraka@cs.tut.fi. Koko kurssin henkilökunta lukee kurssin sähköposteja. OHJ-2010 Tietorakenteiden käyttö 18 1.9 Materiaali Kurssin virallisena materiaalina toimii luentomoniste "Tietorakenteiden käyttö", johon myös tenttikysymykset pohjautuvat. Kurssin keskeisiä asioita käsitteleviä kirjoja on maailmalla useita. Hyviä opiskeluun sopivia teoksia ovat esim. Cormen, Leiserson, Rivest, Stein: Introduction to Algorithms. MIT Press Levitin: Introduction to the Design & Analysis of Algorithms. Addison Wesley OHJ-2010 Tietorakenteiden käyttö 19 2 Johdanto Mietitään ensin hiukan syitä tietorakenteiden ja algoritmien opiskelulle OHJ-2010 Tietorakenteiden käyttö 20 2.1 Miksi? Tietokoneohjelmia ei ole olemassa ilman algoritmeja algoritmeihin törmäät esimerkiksi seuraavissa sovelluksissa:

OHJ-2010 Tietorakenteiden käyttö 21 OHJ-2010 Tietorakenteiden käyttö 22 aina, kun käytät tietokonetta, käytät myös algoritmeja. OHJ-2010 Tietorakenteiden käyttö 23 OHJ-2010 Tietorakenteiden käyttö 24 Tietorakenteita tarvitaan ohjelmissa käsiteltävän tiedon tallettamiseen ja sen käsittelyn mahdollistamiseen ja helpottamiseen tietorakenteita on monia eivätkä ne kaikki sovi kaikkiin tilanteisiin ohjelmoijan pitää osata valita tilanteeseen sopivin vaihtoehtojen käyttäytyminen, vahvuudet ja heikkoudet on tunnettava Modernit ohjelmointikielet tarjoavat valmiina helppokäyttöisiä tietorakenteita. Näiden ominaisuuksien sekä käyttöön vaikuttavien rajoitteiden tuntemiseksi tarvitaan perustietorakenneosaamista

OHJ-2010 Tietorakenteiden käyttö 25 Kuinka moni on turhautunut ohjelman tai esimerkiksi kännykän hitauteen? toiminnallisuus on toki ensisijaisen tärkeää kaikille ohjelmille, mutta tehokkuus ei ole merkityksetön sivuseikka on tärkeää huomioida ja miettiä ratkaisujaan myös ajan- ja muistinkäytön kannalta valmiin kirjaston käyttö näyttää usein suoraviivaisemmalta kuin onkaan OHJ-2010 Tietorakenteiden käyttö 26 3 Käsitteitä ja merkintöjä Tässä luvussa esitellään kurssilla käytettävää käsitteistöä ja merkintätapoja. Luvussa käsitellään myös pseudokoodiesityksen ja ohjelmointikielisen koodin eroja käyttäen esimerkkinä järjestelyalgoritmia INSERTION-SORT. Näitä asioita käsitellään tällä kurssilla OHJ-2010 Tietorakenteiden käyttö 27 3.1 Tavoitteet Kurssin keskeisenä tavoitteena on antaa opiskelijalle käyttöön peruskoneisto kuhunkin ohjelmointitehtävään sopivan ratkaisun valitsemiseen ja omien ratkaisujen tehokkuuden arvioimiseen karkealla tasolla. Kurssilla keskitytään erityisesti tilanteeseen sopivan tietorakenteen valintaan. Lisäksi käsitellään käytännön tilanteissa usein vastaan tulevia ongelmatyyppejä ja algoritmejä, joilla ne voi ratkaista. Kurssilla keskitytään lähinnä viereisen kuvan mukaisiin hyviin algoritmeihin. Painotus on siis siinä, miten algoritmin ajankulutus kasvaa syötekoon kasvaessa, eikä niinkään yksityiskohtien optimoinnissa. OHJ-2010 Tietorakenteiden käyttö 28 3.2 Peruskäsitteistöä Tällä kurssilla käsitellään perustietorakenteita ja -algoritmeja. Tietorakenne on tietokoneen muistissa oleva alue tai joukko alueita, joille talletetaan tietoa. tietoa pystytään lisäämään ja hakemaan algoritmien avulla. tietorakenteita on useamman tasoisia: tietorakenne voi koostua toisista tietorakenteista Algoritmi on hyvin määritelty laskentamenetelmä, joka ottaa joukon syötteitä ja tuottaa joukon tuloksia

OHJ-2010 Tietorakenteiden käyttö 29 hyvin määritelty = jokainen askel on kuvattu niin tarkasti, että lukija (ihminen tai kone) osaa suorittaa sen jokainen askel on määritelty yksikäsitteisesti samat vaatimukset pätevät askelten suoritusjärjestykselle suorituksen tulee päättyä äärellisen askelmäärän jälkeen Algoritmi ratkaisee jonkin hyvin määritellyn (laskenta)tehtävän. laskentatehtävä määrittelee, missä suhteessa tulosten tulee olla annettuihin syötteisiin esimerkki: taulukon järjestäminen syötteet: jono lukuja a 1, a 2,..., a n tulokset: luvut a 1, a 2,..., a n suuruusjärjestyksessä pienin ensin OHJ-2010 Tietorakenteiden käyttö 30 laskentatehtävän esiintymä eli instanssi saadaan antamalla tehtävän syötteille lailliset arvot järjestämistehtävän instanssiesimerkki: 31, 41, 59, 26, 41, 58 Algoritmi on oikea (correct), jos se pysähtyy ja antaa oikeat tulokset aina kun sille on annettu laillinen syöte. algoritmin tai laskentatehtävän määritelmä saa kieltää osan muodollisesti mahdollisista syötteistä algoritmi voi olla virheellinen kolmella tavalla antaa väärän lopputuloksen kaatuu kesken suorituksen ei koskaan lopeta virheellinenkin algoritmi on joskus hyvin käyttökelpoinen, jos virhetiheys hallitaan! esim. luvun testaus alkuluvuksi OHJ-2010 Tietorakenteiden käyttö 31 Periaatteessa mikä tahansa menetelmä kelpaa algoritmien esittämiseen, kunhan tulos on tarkka ja yksikäsitteinen. yleensä algoritmit toteutetaan tietokoneohjelmina tai laitteistoina käytännön toteutuksessa on otettava huomioon monia insinöörinäkökohtia sopeuttaminen käyttötilanteeseen syötteiden laillisuuden tarkistukset virhetilanteiden käsittely ohjelmointikielen rajoitukset laitteiston ja kielen aiheuttamat nopeus- ja tarkoituksenmukaisuusnäkökohdat ylläpidettävyys modulaarisuus jne. algoritmin idea hukkuu helposti toteutusyksityiskohtien alle OHJ-2010 Tietorakenteiden käyttö 32 Tällä kurssilla keskitytään algoritmien ideoihin ja algoritmit esitetään useimmiten pseudokoodina ilman laillisuustarkistuksia, virheiden käsittelyä yms. Otetaan esimerkiksi pienten taulukoiden järjestämiseen soveltuva algoritmi INSERTION-SORT:

OHJ-2010 Tietorakenteiden käyttö 33 OHJ-2010 Tietorakenteiden käyttö 34 periaate: toiminnan aikana taulukon alkuosa on järjestyksessä ja loppuosa ei osien raja lähtee liikkeelle paikkojen1ja2välistäjaeteneeaskelkerrallaan taulukon loppuun kullakin siirtoaskeleella etsitään taulukon alkuosasta kohta, johon loppuosan ensimmäinen alkio kuuluu uudelle alkiolle raivataan tilaa siirtämällä isompia alkioita askel eteenpäin lopuksi alkio sijoitetaan paikalleen ja alkuosaa kasvatetaan pykälällä 31 31 31 26 26 26 41 41 41 31 31 31 59 59 59 41 41 41 26 26 26 59 41 41 41 41 41 41 59 58 58 58 58 58 58 59 Kurssilla käytetyllä pseudokoodiesityksellä INSERTION-SORT näyttää tältä: INSERTION-SORT(A) (syöte saadaan taulukossa A) 1 for j := 2 to A.length do (siirretään osien välistä rajaa) 2 key := A[j] (otetaan alkuosan uusi alkio käsittelyyn) 3 i := j 1 4 while i > 0 and A[i] > key do(etsitään uudelle alkiolle oikea paikka) 5 A[i + 1] := A[i] (raivataan uudelle alkiolle tilaa) 6 i := i 1 7 A[i + 1] := key (asetetaan uusi alkio oikealle paikalleen) for- yms. rakenteellisten lauseiden rajaus osoitetaan sisennyksillä (kommentit) kirjoitetaan sulkuihin kursiivilla sijoitusoperaattorina on := ( = on yhtäsuuruuden vertaaminen) -merkkillä varustettu rivi antaa ohjeet vapaamuotoisesti tietueen (tai olion) kenttiä osoitetaan pisteen avulla esim. opiskelija.nimi, opiskelija.numero OHJ-2010 Tietorakenteiden käyttö 35 osoittimen x osoittaman tietueen kenttiä osoitetaan merkin avulla esim. x nimi, x numero ellei toisin sanota, kaikki muuttujat ovat paikallisia taulukoilla ja / tai osoittimilla kootun kokonaisuuden nimi tarkoittaa viitettä ko. kokonaisuuteen tuollaiset isommat tietorakenteethan aina käytännössä kannattaa välittää viiteparametreina yksittäisten muuttujien osalta aliohjelmat käyttävät arvonvälitystä (kuten C++-ohjelmatkin oletuksena) osoitin tai viite voi kohdistua myös ei minnekään: NIL OHJ-2010 Tietorakenteiden käyttö 36 3.3 Algoritmien toteutuksesta Käytännön työelämässä teoriaa tulee osata soveltaa käytäntöön. Esimerkki: järjestelyalgoritmin sopeuttaminen käyttötilanteeseen. harvoin järjestetään pelkkiä lukuja; yleensä järjestetään tietueita, joissa on avain (key) oheisdataa (satellite data) avain määrää järjestyksen sitä käytetään vertailuissa oheisdataa ei käytetä vertailuissa, mutta sitä on siirreltävä samalla kuin avaintakin

ÒÐÙ Ú ØÓÖ ØÝÔ Ø Ú ØÓÖ ÒØ Ì ÙÐÙ Ó ÒÐÙ Ó ØÖ Ñ ÒØ Ý ÙÒ Ò ÒØ ÓÖ ½ º Þ µ µß ÚÓ Ò ÖØ ÓÒËÓÖØ Ì ÙÐÙ Ó² µß Û Ð ¼²² º Ø µ Ýµß º Ø ½µ º Ø µ ¹¹ Ý º Ø µ ¹½ ÐÐ º Ø ½µ Ý Ð ÒØÑ Ò µß»» Ø Ò Ö Ø ØØÚ ÒÑÖ Ø ÓÙØ ÒÒ Ø ÙÐÙ ÓÒ Ó Ó¼ººº Ø Ò ÙÒ Ò ÒØ»»ÐÙ Ø Ò Ö Ø ØØÚØ ÓÖ ¼ º Þ µ µß Ì ÙÐÙ Ó µ»»ðùó ÒØ ÙÐÙ Ó Ø Ò º Ø µ Ð Ò ÖØ ÓÒËÓÖØ µ Ø ÓÙØ ÒÒ ½»» Ö Ø ØÒ ÓÖ ¼ º Þ µ µß ± ¼µß»»ØÙÐÓ Ø Ø Ò Ø Ø Ð Ð ß Ø ÓÙØ Ø Ò Ð Ø ÓÙØ Ð Ø ÓÙØ Ø Ò Ð Ð Ø ÓÙØ º Ø µ Ð OHJ-2010 Tietorakenteiden käyttö 37 Edellisessä kappaleessa esitelty INSERTION-SORTissa muuttuisi seuraavalla tavalla, jos siihen lisättäisi oheisdata: 1 for j := 2 to A.length do 2 temp := A[j] 3 i := j 1 4 while i > 0 and A[i].key > temp.key do 5 A[i + 1] := A[i] 6 i := i 1 7 A[i + 1] := temp jos oheisdataa on paljon, kannattaa järjestää taulukollinen osoittimia tietueisiin ja siirtää lopuksi tietueet suoraan paikoilleen OHJ-2010 Tietorakenteiden käyttö 38 Jotta tulokseksi saataisi ajokelpoinen ohjelma, joka toteuttaa INSERTION-SORT:n tarvitaan vielä paljon enemmän. täytyy ottaa käyttöön oikea ohjelmointikieli muuttujien määrittelyineen ja aliohjelmineen tarvitaan pääohjelma, joka hoitaa syötteenluvun ja sen laillisuuden tutkimisen ja vastauksen tulostamisen on tavallista, että pääohjelma on selvästi algoritmia pidempi OHJ-2010 Tietorakenteiden käyttö 39 OHJ-2010 Tietorakenteiden käyttö 40 Otetaan esimerkiksi edellä kuvatun ohjelman toteutus C++:lla:

OHJ-2010 Tietorakenteiden käyttö 41 Ohjelmakoodi on huomattavasti pseudokoodia pidempi ja algoritmille ominaisten asioiden hahmottaminen on siitä paljon vaikeampaa. Tämä kurssi keskittyy algoritmien ja tietorakenteiden periaatteisiin, joten ohjelmakoodi ei palvele tarkoituksiamme. Tästä eteenpäin toteutuksia ohjelmointikielillä ei juurikaan esitetä. OHJ-2010 Tietorakenteiden käyttö 42 4 Tehokkuus ja algoritmien suunnittelu Tässä luvussa pohditaan tehokkuuden käsitettä ja esitellään kurssilla käytetty kertaluokkanotaatio, jolla kuvataan algoritmin asymptoottista käyttäytymistä eli tapaa, jolla algoritmin resurssien kulutus muuttuu syötekoon kasvaessa. Lisäksi esitellään suunnitteluperiaatteet pala kerrallaan ja hajoita ja hallitse. OHJ-2010 Tietorakenteiden käyttö 43 4.1 Kertaluokat Toisinaan (esimerkiksi reaaliaikajärjestelmissä) on tärkeää tietää kuhunkin operaatioon kuluva tarkka aika. Usein se ei kuitenkaan ole tarpeen, vaan riittää tietää, miten algoritmin ajankäyttö muuttuu syötekoon kasvaessa. Tällä menettelytavalla on se etu, ettei se sido laskelmia yhteen tiettyyn prosessoriin, arkkitehtuuriin tai ohjelmointikieleen. Itse asiassa se ei sido meitä edes ohjelmointiin, vaan sillä voi kuvata periaatteessa minkä tahansa peräkkäisiä operaatioita sisältävän toiminnan ajankulutusta kuten myöhemmin näemme. Yksinkertaistamme ajankäytön analyysiä siten, että oletamme kaikkien syötekoosta riippumattomien operaatioiden vievän saman verran aikaa. Emme myöskään välitä siitä, kuinka monta kertaa jokin operaatio suoritetaan kunhan se tehdään vain vakiomäärä kertoja. OHJ-2010 Tietorakenteiden käyttö 44 Tutkimme kuinka monta kertaa algoritmin suorituksen aikana kukin rivi suoritetaan ja laskemme nämä määrät yhteen. Yksinkertaistamme vielä tulosta poistamalla mahdolliset vakiokertoimet ja alemman asteen termit. Näin voidaan tehdä, koska syötekoon kasvaessa riittävästi alemman asteen termit käyvät merkityksettömiksi korkeimman asteen termin rinnalla. Menetelmä ei luonnollisestikaan anna luotettavia tuloksia pienillä syöteaineistoilla, mutta niillä ohjelmat ovat tyypillisesti riittävän tehokkaita joka tapauksessa. Kutsumme näin saatua tulosta algoritmin ajan kulutuksen kertaluokaksi, jota merkitään kreikkalaisella kirjaimella Θ (äännetään theeta ). Otetaan muutama yksinkertainen esimerkki:

OHJ-2010 Tietorakenteiden käyttö 45 esimerkki: taulukon alkioiden summaus 1 for i := 1 to A.length do 2 summa := summa + A[i] jos taulukon A pituus on n, rivi 1 suoritetaan n + 1 kertaa rivi 2 suoritetaan n kertaa ajankulutus kasvaa siis n:n kasvaessa seuraavalla tavalla: n aika = 2n + 1 1 3 10 21 100 201 1000 2001 10000 20001 tästä huomaamme, että n:n arvo dominoi ajankulutusta suoritamme edellä sovitut yksinkertaistukset: poistamme vakiokertoimen ja alemman asteen termin OHJ-2010 Tietorakenteiden käyttö 46 saamme tulokseksi Θ(n) eli kulutettu aika riippuu lineaarisesti syötteen koosta esimerkki: alkion etsintä järjestämättömästä taulukosta 1 for i := 1 to A.length do 2 if A[i] = x then 3 return i tässä tapauksessa suoritusaika riippuu syöteaineiston koon lisäksi sen koostumuksesta eli siitä, mistä kohtaa taulukkoa haluttu alkio löytyy meidän täytyy siis tutkia erikseen parhaan, huonoimman ja keskimääräisen tapauksen ajankulutus parhaassa tapauksessa etsitty alkio on taulukon ensimmäinen alkio löytyy vakioajassa eli ajankulutus on Θ(1) huonoimmassa tapauksessa etsitty alkio on viimeinen tai sitä ei löydy taulukosta lainkaan tällöin rivi 1 suoritetaan n + 1 kertaa ja rivi 2 n kertaa suoritusaika on Θ(n). OHJ-2010 Tietorakenteiden käyttö 47 keskimääräisen tapauksen suoritusajan määrittäminen on kuitenkin selvästi hankalampaa ensimmäisenä meidän täytyy tehdä jonkinlainen oletus keskimääräisestä tai tyypillisestä aineistosta: alkio on taulukossa todennäköisyydellä p (0 p 1) ensimmäinen haettu alkio löytyy taulukon jokaisesta kohdasta samalla todennäköisyydellä nyt voimme laskea suoraan todennäköisyyslaskennan avulla, kuinka monta vertailua keskimäärin joudutaan tekemään todennäköisyys sille, että alkio ei löydy taulukosta on 1 - p, ja tällöin joudutaan tekemään n vertailua todennäköisyys sille, että alkio löytyy kohdasta i, on p/n, ja tällöin joudutaan tekemään i vertailua OHJ-2010 Tietorakenteiden käyttö 48 odotusarvoinen tarvittavien vertailujen määrä saadaan siis seuraavasti: [1 p n + 2 p n + + i p n + n p ] + n (1 p) n mikäli oletamme, että alkio varmasti löytyy taulukosta eli p = 1, saamme tulokseksi (n+1)/2 eli Θ(n) koska myös tapaus, jossa alkio ei löydy taulukosta, on ajankäytöltään lineaarinen, voimme olla varsin luottavaisia sen suhteen, että keskimääräinen ajankäyttö on kertaluokassa Θ(n) kannattaa kuitenkin muistaa, että läheskään aina kaikki syötteet eivät ole yhtä todennäköisiä, vaan jokaista tapausta on syytä tutkia erikseen

OHJ-2010 Tietorakenteiden käyttö 49 esimerkki: kahden taulukon yhteisen alkion etsintä 1 for i := 1 to A.length do 2 for j := 1 to B.length do 3 if A[i] = B[j] then 4 return A[i] rivi 1 suoritetaan 1.. (n + 1) kertaa rivi 2 suoritetaan 1.. (n (n + 1)) kertaa rivi 3 suoritetaan 1.. (n n) kertaa rivi 4 suoritetaan korkeintaan kerran nopeimmillaan algoritmi on siis silloin kun molempien taulukoiden ensimmäinen alkio on sama parhaan tapauksen ajoaika on Θ(1) OHJ-2010 Tietorakenteiden käyttö 50 pahimmassa tapauksessa taulukoissa ei ole ainuttakaan yhteistä alkiota tai ainoastaan viimeiset alkiot ovat samat tällöin suoritusajaksi tulee 2n 2 + 2n + 1 = Θ(n 2 ) keskimäärin voidaan olettaa, että molempia taulukoita joudutaan käymään läpi noin puoleen väliin tällöin suoritusajaksi tulee Θ(n 2 ) (tai Θ(nm) mikäli taulukot ovat eri mittaisia) OHJ-2010 Tietorakenteiden käyttö 51 4.2 Pala kerrallaan Suoraviivaisin kurssilla käsiteltävistä suunnitteluperiaatteista on pala kerrallaan. alkutilanteessa koko aineisto on prosessoimaton algoritmi prosessoi joka kierroksella palan aineistoa siten, että valmiin aineiston määrä kasvaa, ja prosessoimattoman määrä pienenee lopuksi prosessoimatonta aineistoa ei ole lainkaan, ja algoritmi lopettaa Tämän tyyppiset algoritmit ovat yleensä yksinkertaisia toteuttaa, ja toimivat tehokkaasti pienillä aineistoilla. Jo aiemmin esitelty Insertion-Sort toimii pala kerrallaan. aluksi koko taulukko on (mahdollisesti) epäjärjestyksessä jokaisella kierroksella taulukon alussa olevan järjestetyn alueen koko kasvaa yhdellä pykälällä lopuksi koko taulukko on järjestyksessä OHJ-2010 Tietorakenteiden käyttö 52 INSERTION-SORT INSERTION-SORT( A ) (syöte saadaan taulukossa A) 1 for j := 2 to A.length do (siirretään osien välistä rajaa) 2 key := A[ j ] (otetaan alkuosan uusi alkio käsittelyyn) 3 i := j 1 4 while i > 0 and A[ i ] > key do (etsitään uudelle alkiolle oikea paikka) 5 A[ i + 1 ] := A[ i ] (raivataan uudelle alkiolle tilaa) 6 i := i 1 7 A[ i + 1 ] := key (asetetaan uusi alkio oikealle paikalleen) rivi 1 suoritetaan n kertaa rivit 2 ja 3 suoritetaan n - 1 kertaa rivi 4 suoritetaan vähintään n - 1, enintään (2 + 3 + 4 + + n - 2) kertaa rivit 5 ja 6 suoritetaan vähintään 0, enintään (1 + 2 + 3 + 4 + + n - 3) kertaa

OHJ-2010 Tietorakenteiden käyttö 53 parhaassa tapauksessa, kun taulukko on valmiiksi järjestyksessä, koko algoritmi siis kuluttaa vähintään Θ(n) aikaa huonoimmassa tapauksessa, kun taulukko on käänteisessä järjestyksessä, aikaa taas kuluu Θ(n 2 ) keskimääräisen tapauksen selvittäminen on jälleen vaikeampaa: oletamme, että satunnaisessa järjestyksessä olevassa taulukossa olevista elementtipareista puolet ovat keskenään epäjärjestyksessä. vertailuja joudutaan tekemään puolet vähemmän kuin pahimmassa tapauksessa, jossa kaikki elementtiparit ovat keskenään väärässä järjestyksessä keskimääräinen ajankulutus on pahimman tapauksen ajankäyttö jaettuna kahdella: [(n - 1)n]/ 4 = Θ(n 2 ) OHJ-2010 Tietorakenteiden käyttö 54 4.3 Hajoita ja hallitse Aiemmin on esitetty algoritmien suunnitteluperiaate pala kerrallaan ja siitä esimerkkinä INSERTION-SORT. Nyt esitellään toinen, monesti tehokkaampi suunnitteluperiaate hajoita ja hallitse. ongelma jaetaan alkuperäisen kaltaisiksi, mutta pienemmiksi osaongelmiksi. pienet osaongelmat ratkaistaan suoraviivaisesti suuremmat osaongelmat jaetaan edelleen pienempiin osiin lopuksi osaongelmien ratkaisut kootaan alkuperäisen ongelman ratkaisuksi Palataan edellä mainittuun väitteeseen, jonka mukaan kertaluokkanotaatio ei ole sidottu pelkkiin ohjelmiin ja käsitellään yksi konkreettinen esimerkki: OHJ-2010 Tietorakenteiden käyttö 55 Esimerkki: väärän kultarahan ongelma Kysymyksessä on yleisesti tunnettu logiikkatehtävä. Meillä on n kappaletta kultarahoja, joista yksi on väärä. Väärä kolikko näyttää täsmälleen samalta kuin aidotkin, mutta painaa vähemmän. Meillä on käytössämme yksi vaaka, ja tehtävänä on löytää väärä kolikko. Pala kerrallaan -menetelmällä voimme ratkaista ongelman esimerkiksi ottamalla satunnaisen kolikon, ja vertaamalla sitä yksi kerrallaan kaikkiin muihin kolikoihin. Tällöin punnitsemisia joudutaan suorittamaan vähintään 1 ja korkeintaan n - 1 kappaletta, joten ratkaisun paras tapaus on kertaluokassa Θ(1) ja huonoin ja keskimääräinen tapaus kertaluokassa Θ(n). Vaihtoehtoisesti voidaan ottaa aina kaksi satunnaista kolikkoa ja punnita ne. Tällöin vertailuja tarvitaan korkeintaan n/2 kappaletta, joten ratkaisu on edelleen samassa kertaluokassa. OHJ-2010 Tietorakenteiden käyttö 56 Sama ongelma voidaan kuitenkin ratkaista huomattavasti tehokkaammin hajoittamalla ja hallitsemalla: Asetetaan toiseen vaakakuppiin puolet kolikoista ja toiseen toinen puoli, painavamman kupin kaikki kolikot tiedetään aidoiksi, joten niitä ei tarvitse enää tutkia. Jatketaan samaan tapaan sille puolikkaalle, jossa väärän rahan tiedetään olevan, kunnes vaakakupissa on enää yksi vääräksi tiedetty kolikko. mahdollisesti väärät Ratkaisu on rekursiivinen, ja rekursion pohjan muodostaa tilanne, jossa mahdollisesti vääriä kolikoita on enää yksi. varmasti oikeat

OHJ-2010 Tietorakenteiden käyttö 57 OHJ-2010 Tietorakenteiden käyttö 58 Kolikoiden määrä on jokaisella mittauskerralla 2 potenssiin vielä suoritettavien mittauskertojen määrä (Z): ylimmällä tasolla alkioita on siis 2 Z, joten logaritmin määritelmän pohjalta: 2 Z = n log 2 n = Z Punnituksia tarvitaan siis enää log 2 n kappaletta, mikä suurilla kolikkomäärillä on huomattavasti vähemmän kuin n/2. Ratkaisun kertaluokka on Θ(lg n) sekä pahimmassa että parhaassa tapauksessa. Myös alkioiden järjestäminen voidaan tehdä hajoita ja hallitse -menetelmällä. Otetaan tästä esimerkiksi rekursiivinen järjestelyalgoritmi MERGE-SORT. jaetaan järjestettävä taulukko kahteen osaan jatketaan edelleen osien jakamista kahtia, kunnes osataulukot ovat 0 tai 1 alkion kokoisia 0 ja 1 kokoiset taulukot ovat valmiiksi järjestyksessä eivätkä vaadi mitään toimenpiteitä lopuksi yhdistetään järjestyksessä olevat osataulukot limittämällä 8 1 6 3 6 5 8 1 6 3 6 5 8 1 6 3 6 5 8 1 6 3 6 5 8 1 6 3 6 5 1 6 8 3 6 5 1 6 8 3 6 5 1 6 8 3 5 6 1 6 8 3 5 6 1 3 5 6 6 8 OHJ-2010 Tietorakenteiden käyttö 59 limityksen suorittava MERGE-algoritmi: MERGE( A, l, m, r ) 1 for i := l to r do (käydään koko alue läpi...) 2 B[ i ] := A[ i ] (... ja kopioidaan se aputaulukkoon) 3 i := l (asetetaan i osoittamaan valmiin osan loppua) 4 j := l; k := m + 1 (asetetaan j ja k osoittamaan osien alkuja) 5 while j m and k r do (käydään läpi, kunnes jompikumpi osa loppuu) 6 if B[ j ] B[ k ] then (jos alkuosan ensimmäinen alkio on pienempi...) 7 A[ i ] := B[ j ] (... sijoitetaan se tulostaulukkoon...) 8 j := j + 1 (... ja siirretään alkuosan alkukohtaa) 9 else (muuten...) 10 A[ i ] := B[ k ] (... sijoitetaan loppuosan alkio tulostaulukkoon...) 11 k := k + 1 (... ja siirretään loppuosan alkukohtaa) 12 i := i + 1 (siirretään myös valmiin osan alkukohtaa) 13 if j > m then 14 k := 0 15 else 16 k := m r 17 for j := i to r do (siirretään loput alkiot valmiin osan loppuun) 18 A[ j ] := B[ j + k ] OHJ-2010 Tietorakenteiden käyttö 60 MERGE-SORT MERGE-SORT( A, left, right ) 1 if left < right then (jos taulukossa on alkioita...) 2 mid := ( left + right )/2 (... jaetaan se kahtia) 3 MERGE-SORT( A, left, mid ) (järjestetään alkuosa...) 4 MERGE-SORT( A, mid + 1, right ) (... ja loppuosa) 5 MERGE( A, left, mid, right ) (limitetään osat siten, että järjestys säilyy) MERGE limittää taulukot käyttäen pala kerrallaan -menetelmää. ensimmäinen for-silmukka käyttää osataulukon kokoon nähden lineaarisen määrän aikaa Θ(n) while-silmukka käy osataulukon alkuosan ja loppuosan molemmat läpi korkeintaan kerran ja ainakin toisen puolikkaan kokonaan Θ(n) toinen for-silmukka käy läpi korkeintaan puolet taulukosta, ja käyttää siis pahimmassa tapauksessa aikaa Θ(n) muut operaatiot ovat vakioaikaisia

OHJ-2010 Tietorakenteiden käyttö 61 OHJ-2010 Tietorakenteiden käyttö 62 kun edelliset yhdistetään, saadaan suoritusajaksi Θ(n) sekä parhaassa että pahimmassa tapauksessa. MERGE-SORTIN analyysi ei ole yhtä suoraviivainen, koska se on rekursiivinen algoritmi, ja sen suoritusajan kaava olisi myös rekursiivinen. Rekursiivisen kaavan etsiminen matemaattisesti on kuitenkin tämän kurssin tavoitteiden ulkopuolella, joten tyydymme tutkimaan tilannetta vähemmän formaalilla tavalla. MERGE-SORT kutsuu itseään ja MERGEÄ, kaikki muut operaatiot ovat vakioaikaisia. voidaan siis keskittyä tarkastelemaan MERGEN suorituskertojen kuluttamaa aikaa, kaikki muu on vakioaikaista. 1 1 1 1 1 1 1 1 1 2 4 2 2 4 MERGEN suorituskerroista muodostuu edellisellä sivulla esitetty puurakenne. osataulukoiden koot on merkitty MERGEN instanssien kuviin ensimmäisellä tasolla kaikki osataulukot ovat yhden (tai nollan kokoisia) muilla tasoilla osataulukot ovat aina kaksi kertaa edellisen tason osataulukoiden kokoisia viimeisellä tasolla käsitellään koko taulukkoa jokaisen tason osataulukoiden yhteenlaskettu koko on n yksittäisen tason MERGE-instanssien määrä on 2 kertaa edellisen tason vastaava 2 n 4 2 1 1 log 2 n OHJ-2010 Tietorakenteiden käyttö 63 määrä kasvaa kahden potensseissa, jolloin viimeisen tason instanssien määrä on 2 h, missä h on puun korkeus viimeisellä tasolla instansseja on noin n kappaletta 2 h = n log 2 n = h, siis puun korkeus on log 2 n koska jokaisella tasolla tehdään lineaarinen määrä työtä ja tasoja on lg n kappaletta, koko algoritmin suoritusaika on Θ(n lg n) MERGE-SORT on selvästi monimutkaisempi INSERTION-SORT. Onko sen käytöstä vastaavaa hyötyä? Kyllä, suurilla testiaineistolla ero on selvä. jos n on 1000 000 n 2 on 1000 000 000 000, kun taas nlogn on noin 19 930 000 OHJ-2010 Tietorakenteiden käyttö 64 Käytännön esimerkkejä: MERGE-SORT ja INSERTION-SORT on toteutettu C++:lla, ja niiden suoritusaikoja on mitattu Solaristyöasemalla tammikuussa 2001: n INSERTION-S. MERGE-S. 10 0,01 ms 0,02 ms 100 0,3 ms 0,2 ms 1 000 28 ms 2,7 ms 10 000 2900 ms 37 ms aivan pienillä syötteillä INSERTION-SORT on tehokkaampi kun n = 100, ohjelmat ovat suunnilleen yhtä nopeat kun n = 1000, INSERTION-SORT on jo kymmenen kertaa hitaampi

OHJ-2010 Tietorakenteiden käyttö 65 Introduction to Algorithms; Cormen, Leiserson, Rivest, Stein antaa esimerkin INSERTION-SORTIN ja MERGE-SORTIN tehokkuuserosta: INSERTION-SORTIA ajetaan 100 kertaa nopeammalla koneella kuin MERGE-SORTIA huippuluokan koodari koodaa INSERTION-SORTIN suoraan konekielellä, jolloin vakiokerroin on pieni, ja aikaa kuluu 2n 2 MERGE-SORTIN koodaa keskinkertainen ohjelmoija korkeantason kielellä, ja aikaa kuluu 50n lg n miljoonan numeron järjestämiseen kuluu INSERTION-SORTILLA 2000 sekuntia ja MERGE-SORTILLA noin 100 sekuntia. Jos kasvatetaan järjestettävien lukujen joukko kymmeneen miljoonaan, kasvaa INSERTION-SORTIN suoritusaika noin 2,3 päivään, kun MERGE-SORT selviytyy tehtävästä alle 20 minuutissa. MERGE-SORT on kappaleen 1.1 määritelmän mukainen hyvä algoritmi. OHJ-2010 Tietorakenteiden käyttö 66 4.4 Kertaluokkamerkinnät Tässä luvussa määritellään tarkemmin Θ-merkintä, sekä kaksi muuta saman sukuista merkintää Edellisessä luvussa yksinkertaistimme suoritusajan lauseketta melkoisesti: jätimme jäljelle ainoastaan eniten merkitsevän termin poistimme sen edestä vakiokertoimen kuvastavat algoritmin käyttäytymistä, kun syötekoko kasvaa kohti ääretöntä siis kuvaavat asymptoottista suorituskykyä antavat käyttökelpoista tietoa vain jotain rajaa suuremmilla syötteillä usein raja on varsin alhaalla Θ- yms. merkintöjen mukaan nopein on myös käytännössä nopein, paitsi aivan pienillä syötteillä OHJ-2010 Tietorakenteiden käyttö 67 Θ-merkintä olkoon g(n) funktio luvuilta luvuille Θ(g(n)) on niiden funktioiden f(n) joukko, joille on olemassa positiiviset vakiot c 1, c 2 ja n 0 siten, että aina kun n n 0, niin 0 c 1 g(n) f(n) c 2 g(n) kuvan (c) funktio f(x) = Θ(g(n)) Θ(g(n)) on joukko funktioita tulisi kirjoittaa esim. f(n) Θ(g(n)), mutta näin ei yleensä tehdä c g(n) f(n) f(n) c g(n) c g(n) 2 f(n) c g(n) 1 OHJ-2010 Tietorakenteiden käyttö 68 Funktion f(n) kuuluvuuden kertaluokkaan Θ(g(n)), voi siis todistaa etsimällä jotkin arvot vakioille c 1, c 2 ja n 0 ja osoittamalla, että funktion arvo pysyy n:n arvosta n 0 alkaen suurempana tai yhtäsuurena kuin c 1 g(n) ja pienempänä tai yhtäsuurena, kuin c 2 g(n). Esimerkki: 3n 2 + 5n 20 = Θ(n 2 ) valitaan c 1 = 3, c 2 = 4 ja n 0 = 4 0 3n 2 3n 2 + 5n 20 4n 2 kun n 4, koska silloin 0 5n 20 n 2 yhtä hyvin olisi voitu valita c 1 = 2, c 2 = 6 ja n 0 = 7 tai c 1 = 0,000 1, c 2 = 1 000 ja n 0 = 1 000 tärkeää on vain, että voidaan valita jotkut positiiviset, ehdot täyttävät c 1, c 2 ja n 0 n 0 n n n 0 n0 (a) (b) (c) n

OHJ-2010 Tietorakenteiden käyttö 69 Tärkeä tulos: jos a k > 0, niin a k n k + a k 1 n k 1 + + a 2 n 2 + a 1 n + a 0 = Θ(n k ) toisin sanoen, jos polynomin eniten merkitsevän termin kerroin on positiivinen, Θ-merkintä sallii kaikkien muiden termien sekä e.m. kertoimen abstrahoinnin pois Vakiofunktiolle pätee c = Θ(n 0 ) = Θ(1) Θ(1) ei kerro, minkä muuttujan suhteen funktioita tarkastellaan sitä saa käyttää vain kun muuttuja on asiayhteyden vuoksi selvä OHJ-2010 Tietorakenteiden käyttö 70 O-merkintä O-merkintä on muuten samanlainen kuin Θ-merkintä, mutta se rajaa funktion ainoastaan ylhäältä. asymptoottinen yläraja Määritelmä: O(g(n)) on niiden funktioiden f(n) joukko, joille on olemassa positiiviset vakiot c ja n 0 siten, että aina kun n n 0, niin 0 f(n) c g(n) kuvan (a) funktio f(x) = O(g(n)) pätee: jos f(n) = Θ(g(n)), niin f(n) = O(g(n)) päinvastainen ei aina päde: n 2 = O(n 3 ), mutta n 2 Θ(n 3 ) tärkeä tulos: jos k m, niin n k = O(n m ) jos hitaimman tapauksen suoritusaika on O(g(n)), niin jokaisen tapauksen suoritusaika on O(g(n)) O-merkinnällä on suuri käytännön merkitys, koska esimerkiksi C++-standardin takaamat suoritusajat ilmaistaan usein sillä. OHJ-2010 Tietorakenteiden käyttö 71 Usein algoritmin hitaimman (ja samalla jokaisen) tapauksen suoritusajalle saadaan pelkällä vilkaisulla jokin O-merkinnällä ilmoitettava yläraja. Esimerkki: INSERTION-SORT rivi kerta-aika for j := 2 to A.length do O(n) key := A[j] O(1) i := j 1 O(1) while i > 0 and A[i] > key do O(n) A[i + 1] := A[i] O(1) i := i 1 O(1) A[i + 1] := key O(1) Jolloin pahimmalle tapaukselle saadaan suoritusaika O(n) O(n) O(1) = O(n 2 ) OHJ-2010 Tietorakenteiden käyttö 72 Ω-merkintä (äännetään iso oomega ) Ω-merkintä on muuten täysin samanlainen kuin Θ-merkintä, mutta se rajaa funktion vain alhaalta. asymptoottinen alaraja määritelmä: Ω(g(n)) on niiden funktioiden f(n) joukko, joille on olemassa positiiviset vakiot c ja n 0 siten, että aina kun n n 0, niin 0 c g(n) f(n) kuvan (b) funktio f(x) = Ω(g(n)) määritelmistä seuraa tärkeä tulos: f(n) = Θ(g(n)) jos ja vain jos f(n) = O(g(n)) ja f(n) = Ω(g(n)). jos nopeimman tapauksen suoritusaika on Ω(g(n)), niin jokaisen tapauksen suoritusaika on Ω(g(n)) Käytännön hyötyä Ω-merkinnästä on lähinnä tilanteissa, joissa jonkin ratkaisuvaihtoehdon parhaan tapauksenkin tehokkuus on epätyydyttävä, jolloin ratkaisu voidaan hylätä välittömästi.

OHJ-2010 Tietorakenteiden käyttö 73 Merkintöjen keskinäiset suhteet f(n) = Ω(g(n)) ja f(n) = O(g(n)) f(n) = Θ(g(n)) Kertaluokkamerkinnöillä on samankaltaisia ominaisuuksia kuin lukujen vertailuilla: f(n) = O(g(n)) f(n) = Θ(g(n)) f(n) = Ω(g(n)) a b a = b a b Eli, jos f(n):n korkeimman asteen termi, josta on poistettu vakiokerroin g(n): n vastaava, f(n) = O(g(n)) jne. Huomaa kuitenkin yksi ero: reaaliluvuille pätee aina tasan yksi kaavoista a < b, a = b ja a > b, mutta vastaava ei päde kertaluokkamerkinnöille. Kaikkia funktioita ei pysty mielekkäällä tavalla vertaamaan toisiinsa kertaluokkamerkintöjen avulla (esim. n ja n 1+sinn ). OHJ-2010 Tietorakenteiden käyttö 74 Hieman yksinkertaistava rautalankaesitys: Jos algoritmi on Ω(g(n)), sen resurssien kulutus on ainakin kertaluokassa g(n). vrt. kirja maksaa ainakin noin kympin. Jos algoritmi on O(g(n)), sen resurssien kulutus on korkeintaan kertaluokassa g(n). vrt. kirja maksaa korkeintaan noin kympin. Jos algoritmi on Θ(g(n)), sen resurssien kulutus on aina kertaluokassa g(n). vrt. kirja maksaa suunnilleen kympin. OHJ-2010 Tietorakenteiden käyttö 75 OHJ-2010 Tietorakenteiden käyttö 76 Huomaa, että kaikkien algoritmien kaikkien tapausten suoritusajalle ei välttämättä voida antaa mitään ratkaisua Θ-notaatiolla. Esimerkkinä Insertion-Sort: paras tapaus on Ω(n), mutta ei Ω(n 2 ) pahin tapaus on O(n 2 ), mutta ei O(n) kaikille tapauksille yhteistä Θ-arvoa ei voida määrittää Esimerkki Otetaan funktio f(n) = 3n 2 + 5n + 2. Suoritetaan sille aiemmin sovitut yksinkertaistukset: alemman asteen termit pois vakiokertoimet pois f(n) = Θ(n 2 ) Vakuuttuaksemme asiasta etsimme kertoimet c 1 ja c 2 : 3n 2 3n 2 + 5n + 2 4n 2, kun n 6 c 1 = 3, c 2 = 4 ja n 0 = 6 toimivat f(n) = O(n 2 ) ja Ω(n 2 ) f(n) = Θ(n 2 ) 800 700 600 500 400 300 200 100 800 700 600 500 400 300 200 100 f(n) 0 0 5 10 15 n0 4n² 0 0 5 10 15 n² 3n²

OHJ-2010 Tietorakenteiden käyttö Selvästi kerroin c2 = 4 toimii myös kun g(n) = n3, sillä kun n 6, n3 > n2 f (n) = O(n3) sama pätee kun g(n) = n4... Ja alapuolella kerroin c1 = 3 toimii myös kun g(n) = n lg n, sillä kun n 6, n2 > n lg n f (n) = Ω(n lg n) sama pätee kun g(n) = n tai g(n) = lg n 77 4n² 700 Tähän mennessä algoritmien suorituskykyä on arvioitu lähinnä suoritusajan näkökulmasta. Muitakin vaihtoehtoja kuitenkin on: Voidaan mitata myös esimerkiksi muistinkulutusta tai kaistanleveyttä. 600 3n² 500 400 n0 300 3nlog(n) 200 100 0 3n 0 5 10 OHJ-2010 Tietorakenteiden käyttö 15 79 Lisäksi käytännössä tulee ottaa huomioon ainakin seuraavat seikat: Millä mittayksiköllä resurssien kulutusta mitataan? Miten syötekoko määritellään? Mitataanko huonoimman, parhaan vai keskimääräisen tapauksen resurssien kulutusta? Millaiset syötekoot tulevat kysymykseen? Riittääkö kertaluokkamerkintöjen tarkkuus vai tarvitaanko tarkempaa tietoa? OHJ-2010 Tietorakenteiden käyttö Ajoajan mittayksiköt Muistin käytön mittayksiköt Valittaessa ajoajan mittayksikköä askelta pyritään yleensä mahdollisimman koneriippumattomaan ratkaisuun: Tarkkoja yksiköitä ovat lähes aina bitti, tavu (8 bittiä) ja sana (jos sen pituus tunnetaan). Todelliset aikayksiköt kuten sekunti eivät siis kelpaa. Vakiokertoimet käyvät merkityksettömiksi. Jäljelle jää kertaluokkamerkintöjen tarkkuustaso. 78 4.5 Suorituskykykäsitteitä 800 4n³ OHJ-2010 Tietorakenteiden käyttö askeleeksi voidaan katsoa mikä tahansa enintään vakioajan vievä operaatio. Vakioaikaiseksi tulkitaan mikä tahansa operaatio, jonka ajankulutus on riippumaton syötekoosta. Tällöin on olemassa jokin syötteen koosta riippumaton aikamäärä, jota operaation kesto ei milloinkaan ylitä. Yksittäisiä askeleita ovat esimerkiksi yksittäisen muuttujan sijoitus, if-lauseen ehdon testaus etc. Askeleen rajauksen kanssa ei tarvitse olla kovin tarkka, koska Θ(1) + Θ(1) = Θ(1). Eri tyyppien muistin käyttö on usein tunnettu, joskin se vaihtelee vähän eri tietokoneiden ja kielten välillä. kokonaisluku on yleensä 16 tai 32 bittiä merkki on yleensä 1 tavu = 8 bittiä osoitin on yleensä 4 tavua = 32 bittiä taulukko A[1... n] on usein n <alkion koko> Tarkka muistin käytön arvioiminen on usein mahdollista, joskin huolellisuutta vaativaa. Kertaluokkamerkinnät ovat käteviä silloin, kun tarkka tavujen laskeminen ei ole vaivan arvoista. 80

OHJ-2010 Tietorakenteiden käyttö 81 Jos algoritmi säilyttää yhtäaikaa koko syöteaineiston, niin arvioinnissa kannattaa erottaa syöteaineiston kuluttama muisti muusta muistin tarpeesta. Esimerkki: INSERTION-SORTin lisämuistin tarve on Θ(1) MERGE-SORTin lisämuistin tarve on Θ(n) INSERTION-SORT on muistin tarpeeltaan MERGE-SORTia olennaisesti parempi muistin kokonaistarve on kummallakin Θ(n) jos mitataan kokonaistarvetta, INSERTION-SORT ei Θ-merkinnällä erotu MERGE-SORTista Kannattaa kuitenkin huomata, että esimerkiksi merkkijonon etsintä syötetiedostosta ei talleta yhtäaikaa koko syöteaineistoa, vaan selaa sen läpi. OHJ-2010 Tietorakenteiden käyttö 82 4.6 Algoritmin valinta Merkittävin algoritmin valintaan vaikuttava tekijä on yleensä sen suorituskyky käyttötilanteessa. Muitakin perusteita kuitenkin on: toteutuksen helppous onko valmiina saatavilla sopivaa algoritmia? onko tehokkuuden parannuksesta saatava lisähyöty monimutkaisemman algoritmin toteuttamisen tuottavan lisätyön arvoinen? yksinkertaiseen koodiin ei ehkä jää yhtä helposti virheitä yksinkertaista ratkaisua on helpompi ylläpitää tulosten tarkkuus liukuluvuilla laskettaessa pyöristysvirheiden kertyminen saattaa olla merkittävä ongelma suoritusajan vaihtelu esim. usein signaalinkäsittelyssä suoritusaika ei saa vaihdella yhtään OHJ-2010 Tietorakenteiden käyttö 83 Myös ohjelmointiympäristö saattaa asettaa rajoituksia: monet kielet vaativat, että taulukoille määritellään maksimikoko taulukoihin perustuville algoritmeille tulee käännösaikainen, keinotekoinen yläraja listarakenteilla saadaan algoritmi toimimaan niin kauan, kuin koneessa riittää muistia listarakenteilla muisti voi loppua yllättäen, kiinteillä taulukoilla ei listarakenteet eivät aina sopivia esim. sulautettuihin sovelluksiin joissakin koneissa rekursiolle varattu muistitila on paljon pienempi kuin muu datatila jos muistia kulutetaan paljon, on valittava ei-rekursiivinen algoritmi (tai toteutus) OHJ-2010 Tietorakenteiden käyttö 84 Mikäli suorituskykyä päätetään pitää primäärisenä valintaperusteena, kannattaa pohtia ainakin seuraavia asioita: Onko syöteaineisto niin iso, että asymptoottinen tehokkuus antaa oikean kuvan suorituskyvystä? Saako hitain tapaus olla hidas, jos keskimääräinen suorituskyky on hyvä? Onko muistin käyttö olennainen tekijä? Onko syöteaineistossa säännöllisyyttä, jota voidaan käyttää hyväksi yhdellä ajokerralla? usealla ajokerralla? Onko syöteaineistossa säännöllisyyttä, joka aiheuttaa huonoimman tapauksen realisoitumisen usein jollakin algoritmilla?

OHJ-2010 Tietorakenteiden käyttö 85 Esimerkki: puhelinluettelo operaatiot tilaajan numeron kysely nimen perusteella uuden tilaajan liittäminen luetteloon vanhan tilaajan poisto oletuksia lisäyksiä ja poistoja tarvitaan harvoin kyselyjä tarvitaan usein lisäykset ja poistot tulevat ryhminä 1. yritelmä: järjestämätön taulukko OHJ-2010 Tietorakenteiden käyttö 86 Lisätään uudet tilaajat loppuun: O(1). Etsitään selaamalla alusta (tai lopusta): O(n). Poistetaan siirtämällä viimeinen alkio poistettavan päälle: O(1) + etsintäkulut = O(n). Ratkaisu ei ole hyvä, koska usein tarvittavat operaatiot ovat hitaita. 2. yritelmä: järjestetty taulukko, 1. versio Lisätään uudet tilaajat suoraan järjestyksen mukaiseen paikkaan, ja siirretään loppuja alkioita taaksepäin: O(n). Poistetaan siirtämällä loppuja alkioita eteenpäin O(n). Käytetään etsinnässä puolitushakua: Virtanen Järvinen Lahtinen 123 555 123 111 123 444 1 2 n OHJ-2010 Tietorakenteiden käyttö 87 BIN-SEARCH( A, 1, n, key ) vaatimus: n 1, taulukko on järjestetty 1 low := 1; hi := n (alustetaan etsintäalue kattamaan koko taulukon) 2 while low < hi do (jatketaan etsintää, kunnes etsintäalue on tyhjä) 3 mid := ( low + hi )/2 (puolitetaan etsintäalue) 4 if key A[ mid ] then (jos avain löytyy alemmasta puoliskosta...) 5 hi := mid (...valitaan alempi puolisko uudeksi etsintäalueeksi) 6 else (muuten...) 7 low := mid + 1 (...valitaan ylempi puolisko uudeksi etsintäalueeksi) 8 if A[ low ] = key then 9 return low (etsitty löytyi taulukosta) 10 else 11 return 0 (etsittyä ei löytynyt) BIN-SEARCHIN suoritusaika on Θ(lg n). Nyt usein käytetty etsintä on tehokas, mutta poisto on edelleen hidas, samoin lisäys. Ratkaisu vaikuttaa kuitenkin paremmalta kuin ensimmäinen yritelmä, mikäli alkuperäinen oletuksemme siitä, että hakuja tapahtuu selvästi useammin kuin lisäyksiä ja poistoja, pitää paikkansa. OHJ-2010 Tietorakenteiden käyttö 88 3. yritelmä: melkein järjestetty taulukko Pidetään suurin osa taulukosta järjestettynä, lopussa pieni järjestämätön alue (koko l). vertaa puhelinluettelo + lisälehdet Lisäykset tehdään loppualueelle: O(1). Etsintä tapahtuu ensin puolitushaulla järjestyksessä olevasta alkuosasta ja tarvittaessa selaamalla loppuosasta: O(lg n) + O(l). Poisto suoritetaan jättämällä nimi paikalleen ja asettamalla numeroksi 0: O(1) + etsintäkulut = O(lg n) + O(l). Kun loppualue on kasvanut liian suureksi, järjestetään koko taulukko: Θ(n lg n). Kohtalainen ratkaisu, mutta Θ(l) voi olla iso ajoittainen järjestäminen maksaa