58131 Tietorakenteet ja algoritmit Uusinta- ja erilliskoe 15.6.2018 malliratkaisut ja arvosteluperusteet 1. [10 pistettä] Hakemistorakenteet. Vertaa linkitettyjen listojen, tasapainoisten hakupuiden ja hajautuksen ominaisuuksia hakemistorakenteina: Mitä operaatioita kukin rakenne tukee? Mitkä ovat operaatioiden aikavaativuudet? Mitä muita näiden rakenteiden ominaisuuksia tulee ottaa huomioon toteutettaessa hakemistoa johonkin tiettyyn tarkoitukseen? Vastaa yleisellä tasolla menemättä rakenteiden toteutuksen yksityiskohtiin. Pisteytys: Yleisesti ottaen kunkin mainitun tehtävänannossa mainitun tietorakenteen (lista, hakupuu, hajautustaulu) operaatioiden ja aikavaativuuksien esittämisestä on saanut 3 pistettä ja 1 piste on tullut kommenteista, joissa on vertailtu tietorakenteita keskenään tai annettu muuta relevanttia lisätietoa. Tehtävä on kuitenkin arvioitu kokonaisuutena. Melko vaatimatonkin selitys on riittänyt, jos perusasiat ovat kunnossa. Toisaalta pisteitä on vähennetty virheellisistä tai muuten oudoista selityksistä. 2. [10 pistettä] Taulukoiden vertailu. Syötteenä on annettu kaksi taulukkoa A ja B, joissa on mielivaltaisia kokonaislukuja mielivaltaisessa järjestyksessä. Tehtävänä on tulostaa pienin sellainen taulukon A alkio, joka ei esiinny taulukossa B. Jos kaikki taulukon A alkiot esiintyvät myös taulukossa B, palautusarvon tulee olla Nil. Olkoon n taulukoiden A ja B yhteenlaskettu alkioiden lukumäärä. (a) Esitä tehtävään ratkaisualgoritmi, jonka pahimman tapauksen aikavaativuus on O(n log n). Ratkaisu: Tehtävän voi ratkaista usealla eri tavalla käyttäen järjestämistä tai tasapainotettuja hakupuita. Eräs yksinkertainen menetelmä on seuraava: Järjestä taulukot A ja B lomitusjärjestämisellä (pahimman tapauksen aikavaativuus O(n log n)). Aseta i = 1 ja j = 1. Jos j > B. size tai A[i] < B[j], palauta A[i]. Jos A[i] = B[j], aseta i = i + 1. Muuten aseta j = j + 1. Toista niin kauan kuin taulukkoja riittää. Jos taulukko A loppuu kesken, haluttua arvoa ei ole. Tässä vaiheessa toistetaan vakioaikaista operaatiota O(n) kertaa. Kokonaisaikavaativuudeksi tulee siis O(n log n + n) = O(n log n). Pisteytys: Tehtävänannossa ei pyydetty pseudokoodia, joten täysiin pisteisiin on riittänyt melko karkea kuvaus ratkaisuperiaattesta. Yksi piste on kuitenkin vähennetty, jos jokin oleellinen asia on selitetty epämääräisesti; esim. puhutaan alkion hakemisesta taulukosta B mutta ei mitenkään selitetä, miten siinä käytetään hyväksi taulukon B järjestystä. (b) Esitä tehtävään ratkaisualgoritmi, jonka keskimääräisen tapauksen aikavaativuus (sopivilla oletuksilla) on O(n). Ratkaisu: Muodostetaan taulukon B alkioista hajautustaulu. Käydään taulukko A läpi alkio kerrallaan pitäen kirjaa pienimmästä löydetystä alkiosta. Kunkin alkion kohdalla tarkastetaan ensin, onko se hajautustaulussa. Jos ei ole, sitä verrataan pienimpään aiemmin löydettyyn ja tarvittaessa päivitetään tätä.
Algoritmi tekeen O(n) hajautustauluoperaatiota ja niiden lisäksi O(n) vakioaikaista operaatiota. Jos oletetaan, että käytössä on hyvä hajautusfunktio, yksittäinen hajautusoperaatio vie keskimäärin ajan O(1), jolloin kokonaisaikavaativuudeksi tulee O(n). Pisteytys: Kuten kohdassa (a), periaatteen esittäminen yleisellä tasolla riitti. Neljä pistettä on saanut ratkaisusta, jossa on oletettu taulukoiden alkioiden olevan pieniä ja sovellettu laskemisjärjestämistä tms. kohdan (a) kaltaisessa ratkaisussa. Oletus alkioiden pienuudesta ei sinänsä ole kovin kohtuuton, mutta kuitenkin selvästi rajoittavampi kuin oletus hajautusfunktion toimimisesta, mihin myös rajoitus keskimääräiselle aikavaativuudelle viittasi. 3. [10 pistettä] Binääripuut ja hakupuut. Tehtävä käsittelee binäärihakupuita, joiden ei oleteta välttämättä olevan tasapainoisia. Esitä kummassakin kohdassa ratkaisualgoritmisi yksityiskohtaisena pseudokoodina. (a) Binäärihakupuun kuhunkin sisäsolmuun x halutaan liittää arvo size[x], joka kertoo solmun x jälkeläisten lukumäärän. Esitä algoritmi, joka laskee (muuten valmiiseen) binäärihakupuuhun size-arvot. (Selvennys: tässä vaiheessa ei siis vielä ole mitenkään oleellista, että kysymyksessä on nimenomaan hakupuu.) Ratkaisu: Ongelma ratkeaa kutsumalla seuraavaa rekursiivista proseduuria argumenttina osoitin puun juureen: count-size(x) if x == Nil then return 0 else size[x] = count-size(x. left) + count-size(x. left) + 1 return size[x] Tässä siis on määritelmän mukaisesti laskettu solmu omaksi jälkeläisekseen. Arvostelussa on kuitenkin hyväksytty myös ratkaisut, joissa on laskettu aitoja jälkeläisiä. Pienistä epätarkkuuksista pseudokoodiesityksessä ei ole vähennetty pisteitä, jos tarkoitus on selvästi oikea.
(b) Oletetaan nyt, että binäärihakupuussa on edellisen kohdan mukaiset size-arvot. Esitä tehokas algoritmi, joka saa syötteenä positiivisen kokonaisluvun k ja palauttaa puun k:nneksi suurimman avaimen. Algoritmin pahimman tapauksen aikavaativuuden tulee olla verrannollinen puun korkeuteen. Ratkaisu: suurin(x, k) if x == Nil or k == 0 or k > size[x] then return Nil if x. right == Nil then r = 0 else r = size[x. right] if k r then return suurin(x. right, k) elseif k == r + 1 then return x. key else return suurin(x. left, k r 1) Pienistä epätarkkuuksista pseudokoodiesityksessä ei ole vähennetty pisteitä, jos tarkoitus on selvästi oikea. Yksi tai kaksi pistettä on kutenkin vähennetty pienehköistä virheistä, jotka liittyvät algoritmin toimintalogiikkaan (eikä pseudokoodin ohjelmointitekniikkaan ). 4. [10 pistettä] Yhtenäisyys ja vahva yhtenäisyys. (a) Suuntaamaton verkko G = (V, E) on esitetty vieruslistoina. Ongelmana on selvittää, onko verkko G yhtenäinen. Esitä (pseudokoodina) ratkaisualgoritmi ongelmalle ja analysoi ratkaisusi aikavaativuutta. Täysien pisteiden saamiseksi algoritmin tulee toimia ajassa O( V + E ). Ratkaisu ja pisteytys: Ongelman voi ratkaista suorittamalla leveyssuuntaisen tai syvyyssuuntaisen läpikäynnin mielivaltaisesta alkusolmusta ja tarkistamalla, saavutettiinko kaikki solmut. Täydet 5 pistettä on saanut esittämällä kyseisen algoritmin pseudokoodin suunnilleen luentomateriaalin tarkkuudella ja lyhyen perustelun aikavaativuudelle. Aikavaativuusanalyysin ei tarvinnut olla kovin yksityiskohtainen, mutta jos se oli hyvin puutteellinen, on vähennetty yksi piste. (b) Entä jos G onkin suunnattu: miten selvittäisit ajassa O( V + E ), onko verkko vahvasti yhtenäinen? Kuvaa ratkaisuperiaate sanallisesti (yksityiskohtaista pseudokoodia ei tarvitse esittää) ja perustele sen toimivuus ja aikavaativuus. Älä kuitenkaan käytä hyväksi kurssilla esitettyä vahvasti yhtenäisten komponenttien algoritmia; tarkoitus on esittää tähän rajoitetumpaan ongelmaan yksinkertaisempi algoritmi. Ratkaisu: Ongelman voi ratkaista suorittamalla valitsemalla mielivaltaisen solmun u ja suorittamalla siitä lähtien syvyyssuuntaisen (tai leveyssuuntaisen) läpikäynnin sekä verkossa G että sen transpoosiverkossa G T. Jos kumpikin läpikäynti löytää verkon kaikki solmut, verkko on vahvasti yhtenäinen; muuten ei ole. Algoritmin aikavaativuus on sama kuin syvyyssuuntaisen läpikäynnin eli O( V + E ). Perustellaan, että algori toimii oikein.
Verkko on vahvasti yhtenäinen, jos ja vain jos minkä tahansa kahden solmun välillä on polku kumpaankin suuntaan. Tämä on sama kuin että mistä tahansa solmusta x on polku mihin tahansa solmuun y sekä alkuperäisessä verkossa että transpoosiverkossa. Jos tämä ehto pätee, niin erityisesti solmusta u pääsee kaikkiin muihin solmuihin, ja algoritmi toteaa verkon vahvasti yhtenäiseksi. Kääntäen jos algoritmi toteaa verkon vahvasti yhtenäiseksi, niin millä tahansa solmuilla x ja y on olemassa polut u x ja u y sekä alkuperäisessä että transpoosiverkossa. Siis alkuperäisessä verkossa on polut x u, y u, u x ja u y, joten polut x y ja y x voidaan muodostaa solmun u kautta; verkko on vahvasti yhtenäinen. Pisteytys: Tehtävä oli tarkoitettu hieman haastavammaksi algoritmilaatimistehtäväksi, joten pisteiden saaminen on edellyttänyt jotain selvää ideaa siitä, miten annetun ongelman voisi ratkaista annetun aikavaativuuden puitteissa. Toimivan algoritmin esittämisestä on saanut 4 pistettä ja sen toimivuuden perustelusta yhden pisteen. Monessa ratkaisuyrityksessä mainittiin topologinen järjestäminen. Topologinen järjestys on määritelty vain syklittömissä verkoissa, ja vahvasti yhtenäisissä verkoissa on aina syklejä, joten tämä ei ainakaan sellaisenaan ole sovellettavissa. 5. [10 pistettä] Dijkstran algoritmi. Selitä lyhyesti, miten Dijkstran algoritmi löytää verkossa lyhimmät polut, ja havainnollista selitystäsi parilla kuvalla. Esitä myös Dijkstran algoritmi pseudokoodina ja analysoi sen aikavaativuus. Algoritmin oikeellisuutta ei tarvitse todistaa. Algoritmin tarvitsemien tietorakenteiden aikavaativuudet voi olettaa tunnetuksi, mutta sano kuitenkin aina selvästi, mitä tietorakennetta tai aikavaativuutta milloinkin käytät. Pisteytys: Selitys ja esimerkki 6 pistettä. Arvostelussa on kiinnitetty huomiota siihen, että teksti ja kuvat kokonaisuutena osoittavat, että algoritmin perusajatus on ymmärretty oikein. Jos selitys on perusteellinen, kevyempi esimerkki on riittänyt, ja toisin päin. Pseudokoodi 2 pistettä. Täysiin pisteisiin on vaadittu suunnilleen luentomateriaalin pseudokoodia vastaava tarkkuustaso ja mahdollisten apuproseduurien (paitsi keko-operaatioiden) avaaminen. Aikavaativuusanalyysi 2 pistettä. Tässä on vaadittu nimenomaan aikavaativuuden analysoimista eli keskeisesti sen selittämistä, miten se muodostuu tunnetuista keko-operaatioiden aikavaativuuksista. 6. [10 pistettä] Paras polku. Määritellään suuntaamattomassa painotetussa verkossa polun kustannukseksi suurin polulla olevan yksittäisen kaaren paino. Tehtävänä on löytää kahden annetun verkon solmun välille kustannukseltaan pienin polku. Verkon voi olettaa yhtenäiseksi. Esitä tehtävään tehokas ratkaisualgoritmi. Perustele täsmällisesti, että se toimii oikein, ja perustele myös sen aikavaativuus. Algoritmille ei tarvitse esittää yksityiskohtaista pseudokoodia, riittää selittää sen toimintaperiaate. Voit käyttää algoritmissa
ja sen aikavaativuusanalyysissa kaikkia kurssilta tunnettuja algoritmeja ja tietorakenteita ja niihin liittyviä aikavaativuuksia. Sano kuitenkin selvästi, mitä tunnettua aikavaativuutta jne. milloinkin käytät. Ratkaisu 1: Muodostetaan verkon pienin virittävä puu Primin tai Kruskalin algoritmilla. Haluttu polku on nyt annettuja solmuja yhdistävä puun kaaria pitkin kulkeva polku. Aikavaativuus on sama O( E log E ) kuin Primillä ja Kruskalilla. Oikeellisuuden toteamiseksi olkoot verkossa G = (V, E) annetut solmut s ja t, ja olkoon (V, T ) pienin virittävä puu. Olkoon P puuta pitkin kulkeva polku solmusta s solmuun t. Tehdään vastaoletus, että jokin toinen polku P on parempi kuin P. Olkoon e polun P painavin kaari. Verkossa (V, T { e }) on kaksi komponenttia, ja s ja t kuuluvat eri komponentteihin. Jokin polun P kaari e yhdistää näitä komponentteja. Koska P on parempi kuin P, polun P kaikki kaaret ovat kevyempiä kuin polun P painavin kaari e. Siis virittävän puu (V, T { e } { e }) on kevyempi kuin (V, T ); ristiriita. Ratkaisu 2: Käytetään Dijkstran algoritmia, jossa Relax-operaatiossa summa distance[u]+w(u, v) korvataan maksimilla max { distance[u], w(u, v) }. Aikavaativuus on Dijkstran O(( V + E log V )). Ratkaisun oikeellisuuden tarkastelemiseksi todetaan ensin, että kysymyksessä on lyhimmän polun löytäminen, kun polun pituuden määritelmässä vaihdetaan kaarten painojen yhteenlaskun tilalle maksimin ottaminen. Tarkastelemalla Dijkstran algoritmin oikeellisuustodistusta voidaan havaita, että kaikki sen päättelyaskelet ovat valideja myös tätä etäisyysmittaa käytettäessä. (Huomaa, että negatiiviset kaaret eivät ole ongelma, koska maksimioperaatiota käytetäessä kaaren lisääminen ei koskaan pienennä polun pituutta, toisin kuin yhteenlaskulla negatiivisen painon kanssa.) Pisteytys: Algoritmista on annettu 8 pistettä, joista yksi aikavaativuuden toteamisesta, ja oikeellisuuden perustelusta 2 pistettä. Selvästi edellä esitettyjä tehottomammista ratkaisuista (esim. Bellman-Ford) on vähennetty 2 pistettä.