Transcript PowerPoint
Opintojakso TT00AA11
Ohjelmoinnin jatko (Java): 3 op
Tietorakenneluokkia 2: HashMap, TreeMap
Tietorakenneluokkia ja -rajapintoja
«interface»Collection
«interface»Map
«interface»
Set
«interface»
List
HashMap
ArrayList
«interface»
SortedMap
TreeMap
Java tarjoaa laajan kokoelman tietorakennerajapintoja ja luokkia.
Aiemmin tutustuttiin ArrayList-luokkaan.
Collection-rajapinnan toteuttajat ovat tietorakenteita
olioille.
Map-rajapinnan toteuttajat ovat tietorakenteita avain/arvopareille.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
2
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.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
3
Esimerkki
Esimerkissä on tallennettu puhelinliittymien
liittymänumerot ja liittymien saldot.
avaimena liittymänumero
arvona saldo
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
4
Määrittely ja alustus Java-kielessä
Map <avaimen_tyyppi, arvon_tyyppi> rakenteen_nimi =
new HashMap <avaimen_tyyppi, arvon_tyyppi>();
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 Maprajapinnan ilmentymänä.
Toteuttava luokka voidaan tällöin vaihtaa helposti.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
5
Map-rajapinnan metodeja
arvon_tyyppi get(Object avain)
palauttaa avainta vastaavan arvo-olion .
boolean containsKey(Object avain)
palauttaa tiedon, esiintyykö avain avainten joukossa
boolean containsValue(Object arvo)
palauttaa tiedon, esiintyykö arvo arvojen joukossa .
arvon_tyyppi remove(Object avain)
poistaa avaimen määräämän avain-arvoparin.
void clear()
tyhjentää hajautustaulukon.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
6
Map-rakenteen iterointi
for (Map.Entry<avaimen_tyyppi, arvon_tyyppi>
alkion_nimi : rakenteen_nimi.entrySet()) {
// …
}
Iterointi onnistuu for/each-rakenteella (yllä).
Map-rajapinnan metodi entrySet() palauttaa Setrajapinnan edustajan, jonka alkiot ovat Map.Entryrajapinnan mukaisia avain-arvo pareja.
Set-rajapinta on iteroitavissa for/each-rakenteella.
Map.Entry-rajapinta määrittelee metodit
avaimen_tyyppi getKey()
palauttaa avaimen
arvon_tyyppi getValue()
palauttaa arvon
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
7
import java.util.*;
public class Puhelinliittymat {
Esimerkki
public static void main(String[] args) {
Map<String, Double> liittymat = new HashMap<String, Double>();
liittymat.put("040-1234567",
liittymat.put("041-8800262",
liittymat.put("043-4837263",
liittymat.put("044-3472897",
102.40); // autoboxing double -> Double
17.15);
0.00);
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());
}
}
}
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 (total time: 1 second)
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.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
8
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 TreeMaprakenteeksi (ja kääntäen) muuttamalla luotavan
rakenteen todellinen tyyppi yhdessä lauseessa:
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
9
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());
}
}
Iteratorrajapinta
}
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 Iteratoriterointirajapinnan edustajan.
Iterator-rajapinta sisältää mm. metodit :
boolean hasNext()
alkion_tyyppi next()
Täsmälleen sama
tulostus kuin sivulla 8
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
10
Esimerkki
Luodaan videovuokraamolle tietorakenne, jossa
videovuokraamossa pidetään kirjaa
elokuvista
niiden tallenteista
Videovuokraamo tuntee tallenteensa.
Tallennetaan ne HashMap-rakenteeseen.
Saavutetaan nopea haku tallennenumeron
perusteella.
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
11
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;
}
}
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
12
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();
}
}
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
13
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);
}
run:
}
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);
Esimerkki:
Luokka
Videovuokraamo
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
(total time: 1 second)
// 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();
}
}
20.9.2012
Vesa Ollikainen & Outi Grotenfelt
14
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
15
THANK YOU!
www.metropolia.fi/en/
www.facebook.com/MetropoliaAMK
[email protected]