160 likes | 276 Views
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 .
E N D
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. Map <avaimen_tyyppi, arvon_tyyppi> rakenteen_nimi = new HashMap <avaimen_tyyppi, arvon_tyyppi>(); Vesa Ollikainen & Outi Grotenfelt
Map-rajapinnan metodeja • arvon_tyyppiget(Objectavain) • palauttaa avainta vastaavan arvo-olion. • booleancontainsKey(Objectavain) • palauttaa tiedon, esiintyykö avain avainten joukossa • booleancontainsValue(Objectarvo) • palauttaa tiedon, esiintyykö arvo arvojen joukossa. • arvon_tyyppiremove(Objectavain) • poistaa avaimen määräämän avain-arvoparin. • voidclear() • 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_tyyppigetKey() • palauttaa avaimen • arvon_tyyppigetValue() • palauttaa arvon for (Map.Entry<avaimen_tyyppi, arvon_tyyppi> alkion_nimi : rakenteen_nimi.entrySet()) { // … } Vesa Ollikainen & Outi Grotenfelt
import java.util.*; public class Puhelinliittymat { public static void main(String[] args) { Map<String, Double> liittymat = new HashMap<String, Double>(); liittymat.put("040-1234567", 102.40); // autoboxing double -> Double liittymat.put("041-8800262", 17.15); liittymat.put("043-4837263", 0.00); liittymat.put("044-3472897", 219.36); System.out.println(liittymat.get("041-8800262")); System.out.println(liittymat.get("020-1001001")); for (Map.Entry<String, Double> liittyma: liittymat.entrySet()){ System.out.println("Liittymän "+liittyma.getKey()+" saldo on "+ liittyma.getValue()); } } } 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. run: 17.15 null Liittymän 044-3472897 saldo on 219.36 Liittymän 043-4837263 saldo on 0.0 Liittymän 040-1234567 saldo on 102.4 Liittymän 041-8800262 saldo on 17.15 BUILD SUCCESSFUL (totaltime: 1 second) Vesa Ollikainen & Outi Grotenfelt
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
import java.util.*; public class Puhelinliittymat { public static void main(String[] args) { …. Iterator<Map.Entry<String, Double>> i=liittymat.entrySet().iterator(); while (i.hasNext()){ Map.Entry<String, Double> liittyma = i.next(); System.out.println("Liittymän "+liittyma.getKey()+" saldo on "+ liittyma.getValue()); } } } 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: • booleanhasNext() • alkion_tyyppinext() Täsmälleen sama tulostus kuin sivulla 8 Vesa Ollikainen & Outi Grotenfelt
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
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<Integer, Tallenne> dvdt = new HashMap<Integer, Tallenne>(); 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 12648 System.out.print(dvdt.get(12648)); // hae kaikki tallenteet for (Map.Entry<Integer, Tallenne>dvd : dvdt.entrySet()){ System.out.println(dvd.getValue()); } } public static void main(String[] args){ Videovuokraamo munMaku = new Videovuokraamo(); munMaku.operoi(); } } Esimerkki: Luokka Videovuokraamo run: 12648 James Bond 5 213002 Transformers 5 1836 Transformers 5 13003 Transformers 5 13000 Transformers 5 13001 Transformers 5 12649 James Bond 5 2 12648 James Bond 5 2BUILD SUCCESSFUL (totaltime: 1 second) Vesa Ollikainen & Outi Grotenfelt
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 nimi
THANK YOU! www.metropolia.fi/en/ www.facebook.com/MetropoliaAMK outi.grotenfelt@metropolia.fi