Tietorakenteet, laskuharjoitus 7, ratkaisuja 1. Opiskelijarekisteri-luokka saadaan toteutetuksi käyttämällä kahta tasapainotettua binäärihakupuuta. Toisen binäärihakupuun avaimina pidetään opiskelijoiden nimiä ja toisessa puussa avaimina toimivat opiskelijanumerot. Javatoteutuksessa käytetään Javan valmista binäärihakupuuluokkaa (TreeMap). import java.util.treemap; import java.util.map; class Opiskelijarekisteri { private TreeMap<String, Opiskelija> nimella; private TreeMap<String, Opiskelija> numerolla; public Opiskelijarekisteri() { nimella = new TreeMap<String, Opiskelija>(); numerolla = new TreeMap<String, Opiskelija>(); Rekisteriin lisättävät oliot lisätään molempiin hakupuihin käyttäen eri avaimia. Vastaavasti haku tehdään puuhun, joka on järjestetty hakukriteerin mukaisesti. public void lisaaopiskelija(opiskelija o) { nimella.put(o.getnimi(), o); numerolla.put(o.getopnro(), o); public Opiskelija haenimenperusteella(string haettava) { return nimella.get(haettava); public Opiskelija haenumeronperusteella(string haettava) { return numerolla.get(haettava); Nimien tulostukseen halutussa järjestyksessä on useita tapoja. Suoraviivaisin tapa lienee tulostaa TreeMapin keyset()-metodin palauttaman joukon alkiot. Joskus tahdotaan iteroida TreeMappiin talletetut avain-arvo-parit. Jälkimmäinen metodi näyttää tästä esimerkin. public void tulostanimetaakkosjarjestyksessa() { for(string nimi : nimella.keyset()) 1
System.out.println(nimi); public void tulostaopiskelijanumerot() { for(map.entry<string, Opiskelija> pari : numerolla.entryset()) System.out.println(pari.getValue()); Huomaa, että esim. seuraavan metodin suoritusaika olisi O(n log n), koska jokaisella kierroksella puuhun suoritetaan haku. Siis käydäksemme Javassa läpi avain-arvo-parit ajassa O(n), on edellä esitelty tapa ainoa mahdollinen. public void tulostaopiskelijanumerot() { for(string numero : numerolla.keyset()) System.out.println(numerolla.get(numero)); 2. Ohessa on toteutukset luokille Tyontekija ja Yritys. class Tyontekija implements Palkittava { private int palkka; public Tyontekija(int palkka) { this.palkka = palkka; public int palkka() { return palkka; import java.util.arraylist; class Yritys implements Palkittava { private ArrayList<Palkittava> palkittavat; public Yritys() { palkittavat = new ArrayList<Palkittava>(); public void lisaapalkollinen(palkittava p) { palkittavat.add(p); public int palkka() { int summa = 0; 2
for(palkittava p : palkittavat) { summa += p.palkka(); return summa; Palkollisten (Palkittava-rajapinnan toteuttavien olioiden) hierarkia vastaa puurakennetta, jossa lapsien määrää ei ole rajoitettu mitenkään. Puurakenteen lehtisolmuja ovat Tyontekija-oliot ja sisäsolmuja ovat Yritys-oliot. Yritysluokan palkka()-metodi suorittaa syvyyssuuntaisen läpikäynnin tässä puurakenteessa. 3
3. Seuraava kuvasarja näyttää B + -puun muutokset lisäysten jälkeen. Avaimet 33 ja 25 mahtuvat lehtisolmuihin, joten niiden lisäys ei muuta puun rakennetta. Avain 19 ei mahdu lehtisolmuun, joten lehtisolmu täytyy halkaista ja sisäsolmuun ilmestyy uusi viitta-arvo. Tämän jälkeen avain 43 mahtuu lehtisolmuun ja avaimen 49 lisäys aiheuttaa taas lehtisolmun halkaisun. 11 5 8 11 21 29 33 45 51 53 57 1 11 5 8 11 21 25 29 33 45 51 53 57 1 11 25 5 8 11 19 21 25 29 33 45 51 53 57 1 11 25 5 8 11 19 21 25 29 33 43 45 51 53 57 1 11 25 53 1 5 8 11 19 21 25 29 33 43 45 49 51 53 57 1 4. Seuraava kuvasarja näyttää B + -puun muutokset lisäysten jälkeen. Avaimet 1 4 mahtuvat samaan lehtisolmuun. Avaimen 5 lisäyksen jälkeen lehtisolmu täytyy halkaista, jolloin puuhun ilmestyy sisäsolmu. Tämän jälkeen joka toisen avaimen lisäyksen jälkeen lehtisolmu täytyy halkaista. Avaimen 11 lisäyksen jälkeen myös sisäsolmu täytyy halkaista, jolloin sisäsolmuja tarvitaan kaksi kerrosta. 4
1 1 2 1 2 3 1 2 3 4 2 2 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 7 1 2 3 4 5 7 8 1 2 3 4 5 7 8 9 1 2 3 4 5 7 8 9 10 4 2 8 1 2 3 4 5 7 8 9 10 11 4 2 8 1 2 3 4 5 7 8 9 10 11 12 5
5. Seuraava kuvasarja näyttää B + -puun muutokset poistojen jälkeen. Avaimen 5 poisto ei muuta puun rakennetta, koska lehtisolmuun jää riittävästi avaimia. Avaimen 8 poiston jälkeen lehtisolmussa on liian vähän avaimia ja lehtisolmu yhdistetään viereiseen lehtisolmuun, koska avaimet mahtuvat samaan lehtisolmuun. Avaimen poiston jälkeen lehtisolmussa on liian vähän avaimia ja lehtisolmun avaimet tasataan viereisen lehtisolmun kanssa, koska avaimet eivät mahdu samaan lehtisolmuun. 11 8 11 21 29 45 51 53 57 1 11 21 29 45 51 53 57 1 29 11 21 29 45 51 53 57 1. Avaimen 45 poiston jälkeen vierekkäiset lehtisolmut yhdistetään. Tällöin sisäsolmuun jää vain yksi lapsi ja keskitason sisäsolmut yhdistetään. Tämän seurauksena juurisolmuun jää vain yksi lapsi, jolloin se poistetaan. 11 21 29 51 53 57 1