Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Tietorakenneluokkia 2: HashMap, TreeMap
Tietorakenneluokkia ja -rajapintoja Java tarjoaa laajan kokoelman tietorakennerajapintoja ja - luokkia. Aiemmin tutustuttiin ArrayList -luokkaan. Collection -rajapinnan toteuttajat ovat tietorakenteita olioille. Map -rajapinnan toteuttajat ovat tietorakenteita avain- /arvopareille. Vesa Ollikainen & Outi Grotenfelt
Assosiatiivinen taulukko Assosiatiivisella taulukolla (hajautustaululla) tarkoitetaan tietorakennetta, jossa tieto koostuu avain-arvopareista tieto haetaan avaimen arvon perusteella Tieto voidaan hakea nopeasti avaimen arvon perusteella. avaimen arvosta lasketaan ns. hajautusarvo, jonka perusteella tieto löytyy oikeasta muistipaikasta nopeasti. vrt. tavallinen (indeksoitu) taulukko, jossa tieto löytyy nopeasti indeksin arvon perusteella. Vesa Ollikainen & Outi Grotenfelt
Esimerkki Esimerkissä on tallennettu puhelinliittymien liittymänumerot ja liittymien saldot. avaimena liittymänumero arvona saldo Vesa Ollikainen & Outi Grotenfelt
Määrittely ja alustus Java-kielessä Java-kielessä on HashMap -luokka, joka toteuttaa hajautustaulurakenteen. Alkiot tallennetaan satunnaisessa järjestyksessä. HashMap -luokka toteuttaa Map -rajapinnan, joka on tarkoitettu avain-arvoparien tallentamiseen. Versiosta JDK 5.0 alkaen Java-kielessä oleva geneerisyys vaatii määrittämään avainten ja arvojen tyypit luontivaiheessa. Luotavaa HashMap -oliota suositellaan käsiteltäväksi Map - rajapinnan ilmentymänä. Toteuttava luokka voidaan tällöin vaihtaa helposti. Vesa Ollikainen & Outi Grotenfelt Map rakenteen_nimi = new HashMap ();
Map-rajapinnan metodeja arvon_tyyppi get(Object avain)getObject palauttaa avainta vastaavan arvo-olion. boolean containsKey(Object avain)containsKeyObject palauttaa tiedon, esiintyykö avain avainten joukossa boolean containsValue(Object arvo)containsValueObject palauttaa tiedon, esiintyykö arvo arvojen joukossa. arvon_tyyppi remove(Object avain)removeObject poistaa avaimen määräämän avain-arvoparin. void clear()clear tyhjentää hajautustaulukon. Vesa Ollikainen & Outi Grotenfelt
Map-rakenteen iterointi Iterointi onnistuu for / each -rakenteella (yllä). Map-rajapinnan metodi entrySet() palauttaa Set - rajapinnan edustajan, jonka alkiot ovat Map.Entry - rajapinnan mukaisia avain-arvo pareja. Set -rajapinta on iteroitavissa for/each -rakenteella. Map.Entry -rajapinta määrittelee metodit avaimen_tyyppi getKey()getKey palauttaa avaimen arvon_tyyppi getValue()getValue palauttaa arvon Vesa Ollikainen & Outi Grotenfelt for (Map.Entry alkion_nimi : rakenteen_nimi.entrySet()) { // … }
Esimerkki Esimerkissä tallennetaan neljän puhelinliittymän saldotiedot, haetaan kaksi arvoa avaimen perusteella ja iteroidaan avaimet ja arvot. Huomaa toistuva autoboxing/autounboxing -ominaisuuden soveltaminen. muunnos alkeistietotyypistä kääreluokan edustajaksi ja toisin päin. Vesa Ollikainen & Outi Grotenfelt import java.util.*; public class Puhelinliittymat { public static void main(String[] args) { Map liittymat = new HashMap (); liittymat.put(" ", ); // autoboxing double -> Double liittymat.put(" ", 17.15); liittymat.put(" ", 0.00); liittymat.put(" ", ); System.out.println(liittymat.get(" ")); System.out.println(liittymat.get(" ")); for (Map.Entry liittyma: liittymat.entrySet()){ System.out.println("Liittymän "+liittyma.getKey()+" saldo on "+ liittyma.getValue()); } run: null Liittymän saldo on Liittymän saldo on 0.0 Liittymän saldo on Liittymän saldo on BUILD SUCCESSFUL (total time: 1 second)
TreeMap TreeMap -tietorakenne tallentaa alkiot avainarvojen mukaisessa järjestyksessä. Rakenne on käytännössä hitaampi kuin HashMap. Jos hajautusraketta käsitellään Map -rajapinnan edustajana, voidaan HashMap vaihtaa TreeMap - rakenteeksi (ja kääntäen) muuttamalla luotavan rakenteen todellinen tyyppi yhdessä lauseessa: Vesa Ollikainen & Outi Grotenfelt
Iterator- rajapinta Edellä todettiin, että Set -rajapinta on iteroitavissa. For/each -rakenne on yksinkertaisempi ratkaisu iterointiin. Set-rajapinta toteuttaa myös Collection -rajapinnan vaatiman iterator() -metodin, joka palauttaa Iterator - iterointirajapinnan edustajan. Iterator -rajapinta sisältää mm. metodit : boolean hasNext()hasNext alkion_tyyppi next()next Vesa Ollikainen & Outi Grotenfelt import java.util.*; public class Puhelinliittymat { public static void main(String[] args) { …. Iterator > i=liittymat.entrySet().iterator(); while (i.hasNext()){ Map.Entry liittyma = i.next(); System.out.println("Liittymän "+liittyma.getKey()+" saldo on "+ liittyma.getValue()); } } Täsmälleen sama tulostus kuin sivulla 8
Esimerkki Luodaan videovuokraamolle tietorakenne, jossa videovuokraamossa pidetään kirjaa elokuvista niiden tallenteista Videovuokraamo tuntee tallenteensa. Tallennetaan ne HashMap -rakenteeseen. Saavutetaan nopea haku tallennenumeron perusteella. Vesa Ollikainen & Outi Grotenfelt
Vesa Ollikainen & Outi Grotenfelt Esimerkki: Luokka Leffa public class Leffa { private String nimi; private int hinta; public Leffa(String nimi, int hinta){ this.nimi = nimi; this.hinta = hinta; } public String toString(){ return nimi + " " + hinta; }
Vesa Ollikainen & Outi Grotenfelt Esimerkki: Luokka Tallenne public class Tallenne { private int tallenneKoodi; private Leffa elokuva; public Tallenne(int tallenneKoodi, Leffa elokuva){ this.tallenneKoodi = tallenneKoodi; this.elokuva = elokuva; } public String toString(){ return tallenneKoodi + " " + elokuva.toString(); }
Vesa Ollikainen & Outi Grotenfelt import java.util.*; public class Videovuokraamo { private Leffa movie1, movie2; private Map dvdt = new HashMap (); private void rekisteroi(Leffa movie, int lkm, int ekakoodi){ for (int i=ekakoodi; i<ekakoodi+lkm; i++){ Tallenne dvd = new Tallenne(i, movie); dvdt.put(new Integer(i), dvd); } private void operoi(){ movie1 = new Leffa("James Bond 5", 2); movie2 = new Leffa("Transformers", 5); rekisteroi(movie1, 2, 12648); rekisteroi(movie2, 1, 1836); rekisteroi(movie2, 4, 13000); // hae tallenne System.out.print(dvdt.get(12648)); // hae kaikki tallenteet for (Map.Entry dvd : dvdt.entrySet()){ System.out.println(dvd.getValue()); } public static void main(String[] args){ Videovuokraamo munMaku = new Videovuokraamo(); munMaku.operoi(); } Esimerkki: Luokka Videovuokraamo run: James Bond Transformers Transformers Transformers Transformers Transformers James Bond James Bond 5 2BUILD SUCCESSFUL (total time: 1 second)
Uutta ja vanhaa Javaa Ennen JDK 5.0 -versiota tietorakenneluokkien käsittely oli hankalampaa: Ei geneerisyyttä. Rakenteisiin voitiin tallentaa mitä tahansa olioita. Tyypinmuunnoksista oli huolehdittava itse. Ei automaattista käärimistä alkeistyypeille ja takaisin (autoboxing/autounboxing). Ei for/each -rakennetta. Luotava Iterator -rajapinnan ilmentymä. Kalvosarjan tekijän nimi15
THANK YOU!