Tietorakenteet ja algoritmit, kevät 201 Kurssikoe 1, ratkaisuja 1. Tehtävästä sai yhden pisteen per kohta. (a) Invariantteja voidaan käyttää algoritmin oikeellisuustodistuksissa Jokin väittämä osoitetaan invariantiksi näyttämällä, että 1. invariantti on voimassa tultaessa ensimmäistä kertaa toistolauseeseen 2. invariantti pysyy totena jokaisen toistolauseen rungon suorituksen jälkeen Askelien 1 ja 2 voimassaolosta seuraa se, että jos invariantti on aluksi tosi, pysyy se voimassa koko loopin suorituksen ajan Erityisesti invariantti on vielä totta siinäkin vaiheessa kun loopin suoritus loppuu. Jos invariantti on valittu järkevästi, niin toistolauseen loppuminen yhdessä invariantin voimassaolon kanssa takaa halutun lopputuloksen (b) Binäärihakupuu on ensinnäkin binääripuu, eli jokaisella solmulla on korkeintaan 2 lasta. Lisäksi sille pätee binäärihakupuuehto: jos solmu v on solmun x vasemmassa alipuussa, niin v.key < x.key jos solmu o on solmun x oikeassa alipuussa, niin o.key > x.key (c) Universaalihajautus: valitaan jokaisella ohjelman suorituskerralla satunnainen hajautusfunktio sopivien hajautusfunktioiden perheestä, joka millä tahansa avainten jakaumalla on keskimäärin hyvä. Toteutus: Valitaan alkuluku p joka on vähintään yhtä suuri kuin talletettavien avainten lukumäärä n. Valitaan satunnaisesti kaksi kokonaislukua a ja b väliltä 1 a < p ja 0 b < p. Muodostetaan hajautusfunktio seuraavasti: h(k) = ((a k + b) mod p) mod m (d) Kokeilujono: Avoimessa hajautuksessa kaikki avaimet talletetaan hajautustauluun. Jos paikka T[h(k)] on varattu, etsitään avaimelle k jokin muu paikka taulusta. Uusikin paikka voi olla varattu, tällöin jatketaan etsimistä edelleen. Ne paikat joihin avainta k yritetään laittaa muodostavat k:n kokeilujonon. Huom. Kokeilujono on eri asia kuin kokeilufunktio. 2. Tehtävästä sai 2 pistettä per kohta. (a) L on listan tunnussolmu, joten se ei voi olla null. Algoritmi lisäämiselle loppuun: lisaa(l,k) solmu = new Solmu solmu.key = k solmu.next = null s = L while s.next!= null s = s.next s.next = solmu 1
Algoritmin tilavaativuus on vakio, sillä se käyttää vain kahta apumuuttujaa. Aikavaativuus on O(n), missä n on listan pituus, sillä joudumme käymään listan kokonaisuudessaan läpi löytääksemme viimeisen paikan. (b) Listan ollessa rengaslista pääsemme viimeiseen alkioon listan ensimmäisen jäsenen prev-linkin avulla: lisaa(l,k) solmu = new Solmu solmu.key = k if (L!= null) L.prev.next = solmu solmu.prev = L.prev L.prev = solmu solmu.next = L else solmu.next = solmu solmu.prev = solmu L = solmu Tilavaativuus on taas vakio ja tällä kertaa saamme aikavaativuudenkin vakioksi. (c) Tällä kertaa saamme linkin poistettavaan solmuun, joten meidän ei tarvitse käydä koko listaa läpi etsiäksemme poistettavaa solmua. poista(l,x) edel = x.prev seur = x.next if edel!= null edel.next = seur else L = seur if seur!= null seur.prev = edel Jälleen algoritmin aika- ja tilavaativuus ovat vakioita. 3. Tehtävästä sai 2 pistettä per kohta. (a) Esijärjestys:,3,1,13,7,16,1 Sisäjärjestys: 1,3,,7,13,1,16 Jälkijärjestys: 1,3,7,1,16,13, 2
(b) Lisätään solmu 15: / 1 7 16 / 1 \ 15 Nyt solmu 16 on alin solmu, joka on epätasapainossa. Koska epätasapainon aiheuttaa solmun 16 vasemman lapsen oikea alipuu, niin teemme ensin kierron vasemmalle ja sitten oikealle. Tuloksena oleva puu: / 1 7 15 1 16 Nyt puu on taas tasapainossa ja voimme lisätä solmun 20: / 1 7 15 1 16 \ 20 Solmu 13 on alin, joka on epätasapainossa. Epätasapainon aiheuttaa solmun 13 oikean lapsen oikea alipuu, joten pelkkä vasemmalle kierto riittää. Tuloksena oleva puu: 3
3 15 / 1 13 16 \ 7 1 20 Nyt puu on jälleen tasapainossa. (c) Kun poistamme solmun 1, niin solmu joutuu epätasapainoon. Voimme korjata tilanteen tekemällä kierron vasemmalle solmusta : 13 16 /\ / 3 7 1 Nyt puu on taas tasapainossa. Seuraavaksi poistamme solmun 13. Solmulla 13 on kaksi lasta, joten sen tilalle tulee solmun 13 seuraaja, eli solmu 1: 1 16 /\ 3 7 Puu on tasapainossa, joten olemme valmiita.. Seuraava algoritmi tarkastaa, ovatko kaksi binääripuuta samanlaiset: samat(a,b) if a == null and b == null return true if a == null or b == null if a.key!= b.key if not samat(a.left,b.left) if not samat(a.right,b.right) return true
Toinen vaihtoehto on tarkastaa, onko puiden sisä-ja esijärjestys (tai sisä- ja jälkijärjestys) samat. Nämä määräävät binääripuun yksikäsitteisesti. 5