Tietorakenteet, 2. kurssikoe 10.4.2002

Tehtävä 1: Arvosteluperusteet ja esimerkkivastaus / Jukka Kohonen

Asteikko

a) 4 pistettä:

b) 4 pistettä:

Tarkennuksia ja huomioita

a)
Poistojen oikeellisuus on arvosteltu sen mukaan, että on lähdetty siitä tilanteesta, johon puu toisen lisäysjonon jälkeen jäi. Eli vaikka lisäykset olisivat menneet väärin, oikein tehdyistä poistoista sai pisteet.

Mutta jos lisäykset ovat menneet niin pieleen, että puu ei ole enää edes hakupuu, voi käydä niin, ettei poistoja ole edes mahdollista tehdä oikein, kun "vasemman maksimi" tai "oikean minimi" ei ole oikealla paikallaan. Silloin ei poistostakaan saanut pistettä.

b)
Kierto sinänsä (linkkien siirtely) osattiin varsin hyvin. Tyypilliset virheet olivat, että korkeuskenttiä ei lainkaan muistettu päivittää, tai ei huomattu, että kierrossa alipuun juuri vaihtuu ja jotenkin pitäisi saada tämä tieto välitettyä alipuun vanhemmalle. Luentomateriaalissa tämä informointi hoidetaan niin, että kiertometodi palauttaa kutsujalleen viitteen alipuun uuteen juureen, ja kutsuja sijoittaa saamansa viitteen sinne, minne se kuuluu, ks. esimerkkivastaukset alempana.

(Muitakin tapoja on, esim. jos solmuille oletetaan "isäviitteet" lapsiviitteiden lisäksi, voi kiertometodi tietysti käydä suoraan muuttamassa isän lapsiviitteen oikeaksi... mutta sitten pitäisi huomioida sekin tilanne, että ollaan koko puun juuressa!)


Eräs esimerkkivastaus:

a)
Tilanne ensimmäisen lisäysjonon (18, 21, 30, 15, 10, 5) jälkeen:

Tilanne toisen lisäysjonon (42, 44, 19, 20, 27) jälkeen:

Tässä puussa 15-solmun vasemman alipuun maksimi on 10 ja oikean alipuun minimi on 18. Tämän näkee sekä niiden numeroarvoista (esim. 18 on ko. alipuun pienin luku) että niiden sijainneista (esim. 18 on ko. alipuun vasemmanpuoleisin solmu).

Kun 15 poistetaan "vasemman maksimi"-periaatteella, nousee siis 10 sen tilalle:

AVL-ominaisuus säilyy: Jokaisen solmun lapsien korkeudet eroavat toisistaan korkeintaan yhdellä. Erityisesti solmun 10 lapsien (5 ja 19) korkeudet ovat 0 ja 1; ja solmun 21 lapsien (10 ja 42) korkeudet ovat 2 ja 2.

Jos sensijaan 15 poistetaan "oikean minimi"-periaatteella, nousee 18 sen tilalle:

AVL-ominaisuus säilyy: Jokaisen solmun lapsien korkeudet eroavat toisistaan korkeintaan yhdellä. Erityisesti solmun 18 lapsien (10 ja 19) korkeudet ovat 1 ja 1.

Kuvat on tehty osoitteesta http://www.seanet.com/users/arsen/avltree.html löytyvällä AVL-appletilla.

b)
Selitys:
Yksöis- ja kaksoiskierto ovat paikallisia, vakioajassa O(1) tapahtuvia operaatioita, joilla AVL-ehto saatetaan uudestaan voimaan tietyn "kiertosolmun" kohdalla, siten, että puu edelleen säilyy hakupuuna eli alipuiden sisällöt edelleen noudattavat järjestysrelaatiota. Kierrot tapahtuvat alipuita sopivasti siirtelemällä.

Yksöiskiertoa käytetään, kun liikaa korkeutta on oikean lapsen oikeassa lapsessa (-> kierto vasemmalle) tai vasemman lapsen vasemmassa lapsessa (-> kierto oikealle).

Kaksoiskiertoa käytetään "siksak-tilanteissa": kun liikaa korkeutta on oikean lapsen vasemmassa lapsessa (-> kaksoiskierto vasemmalle) tai vasemman lapsen oikeassa lapsessa (-> kaksoiskierto oikealle).

(Vastaukselta ei vaadittu läheskään näin pitkää selitystä.)

Toteutus:
Kaksoiskierron voi tehdä kahdella yksöiskierrolla, jolloin tietysti yksöiskiertojenkin toteutus on annettava (ks. yksinkertainen kierto ja kaksinkertainen kierto luentomateriaalissa).


  private static AVLSolmu kaksoisKiertoVasemmalle(AVLSolmu k3) {

    k3.oikea = kiertoOikealle(k3.oikea);

    return kiertoVasemmalle(k3);

  }



  private static AVLSolmu kiertoOikealle(AVLSolmu k2) {

    AVLSolmu k1 = k2.vasen;

    k2.vasen = k1.oikea;

    k1.oikea = k2;

    k2.korkeus = maksimi(korkeus(k2.vasen), korkeus(k2.oikea)) + 1;

    k1.korkeus = maksimi(korkeus(k1.vasen), k2.korkeus) + 1;

    return k1;

  }



  private static AVLSolmu kiertoVasemmalle(AVLSolmu k1) {

    AVLSolmu k2 = k1.oikea;

    k1.oikea = k2.vasen;

    k2.vasen = k1;

    k1.korkeus = maksimi(korkeus(k1.oikea), korkeus(k1.vasen)) + 1;

    k2.korkeus = maksimi(korkeus(k2.oikea), k1.korkeus) + 1;

    return k2;

  }



  private static int korkeus(AVLSolmu t) {

    return (t == null) ? -1 : t.korkeus;

  }



  private static int maksimi(int eka, int toka) {

    return (eka > toka) ? eka : toka;

  }

Kaksoiskierron voi tehdä myös kokonaan yhdessä metodissa.