Tietorakenteet JAVA-OHJELMOINTI Osa 5: Tietorakenteita Eero Hyvönen Tietojenkäsittelytieteen laitos Helsingin yliopisto Olioita ja tietoja voidaan organisoida määrämuotoisiksi tietorakenteiksi Hyödyllisiä java.lang -pakkauksen tukemia perusrakenteita ovat mm. Merkkijonot Taulukot Itse voi kehittää mielivaltaisia tietorakenteita Listat, puut, pinot, tietueet, tietämyksen esitysmuodot... Tavallisimpiin löytyy valmiitakin pakkauksia. 3.10.2000 E. Hyvönen: Java Osa 5 2 Sisällys Merkkijonot Taulukot Listat Merkkijonot (String) 3.10.2000 E. Hyvönen: Java Osa 5 3 Luokka String Metodeja (public) Jono merkkityypin (char) alkioita Pituus määräytyy luontihetkellä eikä voi muuttua. Indeksoidaan 0 n-1, missä n on merkkien lukumäärä. Kirjoitetaan "merkit" Esim.: "Kissa", "345.5", " ", "" Lainaamalla "\" voidaan käyttää erikoismerkkejä Esim.: "\tkissa\n", "lainausmerkki \"" Yksittäinen merkki (char) kirjoitetaan 'x' Esim.: 'a', '7', ' ', '\n' "a" on eri asia kuin 'a' 3.10.2000 E. Hyvönen: Java Osa 5 5 int length() Palauttaa merkkien lukumäärän int n = new String("kissa").length(); char charat(int index) Lue merkki 0 length()-1 int indexof(char c) Merkin 1. esiintymän indeksi String touppercase() Muunnos isoihin kirjaimiin String x = "pienellä"; String y = x.touppercase(); // Uusi String olio isolla kirjoitettuna String-luokka ei tarjoa välineitä olion muutteluun Metodin palauttavat uuden kopion, eivät muuta alkuperäistä! Paljon muitakin metodeja (ks. java.lang.string -luokka Javan WWW-dokumentaatiosta) 3.10.2000 E. Hyvönen: Java Osa 5 6 1
Samuuden testauksesta boolean equals(object o) Merkkijonojen vertailu int compareto(string s) Aakkosvertailu <0, jos verrattava olio ennen kuin s 0, jos samat merkkijonot >0, jos verrattava s:n jälkeen == Vertaa vain viitteitä!! String x = "kissa"; // Luo merkkijono-olion String y = "kissa"; // Luo toisen merkkijono-olion System.out.println(x==y); // Tulostuu false! System.out.println(x.equals(y)); // Tulostuu true Esimerkki // Arto Wikla: kappale 2.7.3, s. 69 //--------------------------------------------------- public class JonoVertailu { public static void main(string[] args){ String vastaus; do { System.out.print("Anna ensimmäinen merkkijono: "); String eka = Lue.rivi(); System.out.print("Anna toinen merkkijono : "); String toka = Lue.rivi(); int jarjkoodi = eka.compareto(toka); 3.10.2000 E. Hyvönen: Java Osa 5 7 3.10.2000 E. Hyvönen: Java Osa 5 8 Kertausta if (jarjkoodi < 0) System.out.println("Ensimmäinen on ennen toista."); else if (jarjkoodi == 0) System.out.println("Jonot ovat samat."); else // jarjkoodi > 0 System.out.println("Toinen on ennen ensimmäistä."); System.out.println("\nHaluatko jatkaa? (enter jatkaa!)"); vastaus = Lue.rivi(); while (vastaus.equals("")); // Mitä ovat a ja b seuraavien lauseiden jälkeen? String a = "Jono"; a.touppercase(); String b = a.touppercase(); // Mikä totuusarvo saadaan alla: a="jono"; a=="jono"; // true vain false a.equals("jono"); // true vain false a.compareto("jono"); // Mikä arvo? 3.10.2000 E. Hyvönen: Java Osa 5 9 3.10.2000 E. Hyvönen: Java Osa 5 10 Taulukon idea Taulukko Järjestetty jono alkioita Alkeistyypin alkiota Viittaustyyppejäkin voi taulukoida Moniulotteiset taulukot Taulukon alkioina on toisia taulukoita Taulukkomuuttujan esittely Muoto: tyyppi[] muuttuja; tyyppi muuttuja[]; Esimerkki: int [] vektori; char merkkijono[]; int [][] matriisi; 3.10.2000 E. Hyvönen: Java Osa 5 12 2
Taulukko on olio Luotavissa new-operaattorilla muoto: new tyyppi[koko] Esimerkki: int[] vektori = new int[12]; 12 alkioinen kokonaislukuvektori Alkioille annetaan tyypistä riippuva alkuarvo (esim. 0 tai null) Muuttujanimi kirjoitetaan kuitenkin pienellä Voidaan myös luoda luettelemalla int [] vektori = {1, 5, -7, 99}; Taulukkoja voidaan käyttää myös luokan kenttinä Metodi voi palauttaa arvonaan taulukon Esimerkki: private int [][] metodi() {..} 3.10.2000 E. Hyvönen: Java Osa 5 13 Taulukon esittely/luontitavat int[] a; int[] b = null; int[] c = new int[3]; int[] d = {1, 2, 3}; int[] e = {}; // a:lla ei alkuarvoa // Tyhjä alkuarvo // Taulukko, alkioilla // oletusarvot (tässä 0) // Taulukko, alkiolla // annetut arvot // Taulukko ilman alkioita // Ei kovin hyödyllinen 3.10.2000 E. Hyvönen: Java Osa 5 14 Alkioiden asettaminen Taulukon alkioon viitataan ilmauksella nimi[indeksi]. Esimerkiksi: int y = taulu1[2]; System.out.print(taulu2[n+2]); Alkion arvon voi asettaa uudelleen kuin muuttujan arvon ikään: Esimerkiksi: taulu1[0] = 1; taulu2[n+1] = 3.14; Sääntöjä Ensimmäisen alkion indeksi on 0. Suurin indeksi on siksi konstruktorissa annettu koko - 1. Taulukon koko ei voi muuttua. Koon saa selville muuttujalla length: int [] vektori = {1, 2, 3}; System.out.println(vektori.length); // Tulostaa 3 Alkioilla on tyypistä riippuva oletusarvo 0, 0.0, false, null. 3.10.2000 E. Hyvönen: Java Osa 5 15 3.10.2000 E. Hyvönen: Java Osa 5 16 Esimerkki // Arto Wikla: kappale 2.8.2, s. 75 public class TauluKokeita { public static void main(string[] args) { // Määrittelyitä: int[] klukua; // taulukkomuuttuja, EI vielä taulukkoa! int[] klukub = new int[10]; int[] klukuc = {5, -23, 12, 31, 7}; double[] dlukua = new double[5]; double[] dlukub = {3.14, 7.21, 0.0, 9.1}; // double[4] boolean[] totuusa = new boolean[8]; boolean[] totuusb = {true, true, false}; // boolean[3] String[] jonoa = new String[3]; String[] jonob = {"kissa", "hiiri"}; // String[2] char[] merkkia = new char[10]; char[] merkkib = {'q', 'w', 'e'}; // char[3] 3.10.2000 E. Hyvönen: Java Osa 5 17 // Käyttöä: for (int i=0; i<klukub.length; ++i) // 7:n kertotaulu klukub[i] = 7*(i+1); for (int i=0; i<klukub.length; ++i) System.out.println(klukuB[i]); klukua = klukuc; // KOPIOIDAAN VIITE klukua[1] = 123456; // MYÖS klukuc[1] MUUTTUU! System.out.println(klukuA[1]+" "+klukuc[1]); klukuc = new int[5]; // luodaan uusi taulukko klukuc:n arvoksi klukuc[1] = -98; System.out.println(klukuA[1]+" "+klukuc[1]); 3.10.2000 E. Hyvönen: Java Osa 5 18 3
Esimerkki // Arto Wikla: kappale 2.8.3, s.77 public class BinHae { // Binäärihaku järjestetystä inttaulukosta private static int binhae(int[] taulu, int haettava) { int vasen = 0; int oikea = taulu.length-1; int keski; while (vasen <= oikea) { keski = (vasen+oikea)/2; if (haettava == taulu[keski]) return keski; // löytyi ja lopetetaan! if (haettava < taulu[keski]) oikea = keski-1; else vasen = keski+1; return -1; // hakualue tuli tyhjäksi eikä löytynyt 3.10.2000 E. Hyvönen: Java Osa 5 19 public static void main(string[] args) { // testipääohjelma int[] a = {10, 20, 30, 40, 50}; // tulostus System.out.println(binHae(a, 5)); // -1 System.out.println(binHae(a, 10)); // 0 System.out.println(binHae(a, 20)); // 1 System.out.println(binHae(a, 30)); // 2 System.out.println(binHae(a, 35)); // -1 System.out.println(binHae(a, 40)); // 3 System.out.println(binHae(a, 50)); // 4 System.out.println(binHae(a, 60)); // -1 3.10.2000 E. Hyvönen: Java Osa 5 20 Merkkitaulukko Olioiden taulukointi Merkkijonoja voidaan esittää String-olioina Muuntelussa voi merkkien taulukko olla joustavampi tapa Alkioita voidaan asettaa luomatta uusia jonoja Javassa on valmiit muunnosmetodit public char [] tochararray() Merkkijonosta taulukko public String(char [] array) Taulukosta merkkijono println-metodi on kuormitettu myös char[] tyypille Muunnosta ei tarvita vain tulostamista varten. 3.10.2000 E. Hyvönen: Java Osa 5 21 Taulukossa voi olla alkeistyyppisten alkioiden ohella myös viittaustyyppien olioita Merkkijonotaulukko String [] taulu; // Taulukkomuuttuja // Kuusialkioinen merkkijonojen taulukko: taulu = new String[6]; // Alkiolla oletusarvo taulu = {"Tupu","Hupu","Lupu"}; // Uusi olio arvoksi Esimerkki käytöstä: public static void man(string[] args) { } java-komennon parametrit välitetään merkkijonoina args[0], args[1],... 3.10.2000 E. Hyvönen: Java Osa 5 22 Moniulotteiset taulukot Omien luokkien olioita voi taulukoida samalla tavalla Auto [] autotaulu = new Auto[3]; // Kolme autoa System.out.println(autotaulu[0]); // -> null (oletusarvo) autotaulu[0] = new Auto("Saab"); System.out.println(autotaulu[0]); // Auto-luokan tostring() Toteutustapa: taulukko-olio taulukon alkiona Mielivaltainen määrä ulottuvuuksia mahdollista Taulukon alkiona on taulukko, jonka alkiona on taulukko, jonka alkiona Kaksiuloitteinen tapaus eli matriisi tavallinen Muuttujaesittely: tyyppi [][] muuttuja; Esimerkki: int [][] matriisi; 3.10.2000 E. Hyvönen: Java Osa 5 23 3.10.2000 E. Hyvönen: Java Osa 5 24 4
Moniulotteisen taulukon luonti Esimerkki Luontitapa Muoto: new tyyppi[rivikoko][sarakekoko] Esimerkki: new double [2][3] 2*3 liukulukumatriisi Voidaan myös luetella alkiot riveittäin. int [][] m = {{1,2}, {3,4}, {5,6}}; // 3*2 matriisi Taulukon rivit voivat olla eripituisia! int [][] matriisi = {{1,2}, {3}, null}; 3.10.2000 E. Hyvönen: Java Osa 5 25 int [][] matriisi = { {1,2}, {3,4}, {5,6}}; matriisi[0] tarkoittaa int[] taulukkoa {1, 2}. matriisi[0][1] tarkoittaa int-alkiota 2 alkioiden läpikäynti esim: for (int rivi=0; rivi<matriisi.length; ++rivi) for (sarake=0; sarake<matriisi[rivi].length; ++sarake) System.out.println(matriisi[rivi][sarake]); Matemaattinen tulkinta 3-rivinen matriisi kahdella sarakkeella (3*2) 1 2 // Indeksit alkavat kuitenkin 0:sta eikä 1:stä. 3 4 5 6 3.10.2000 E. Hyvönen: Java Osa 5 26 Vaihtoehtoisia esittelytapoja double a [][][] = new double[10][10][10]; // Ok, mutta... double[] a [][] = new double[10][10][10]; // Huono double[][] a [] = new double[10][10][10]; // Huono double [][][] a = new double[10][10][10]; // Paras Miksi sulkeet heti tyypin perään? int [] t1, t2, t3; // Kaikki ovat taukkomuuttujia -- selkeä tapa. int t1[], t2, t3; // Vain t1 on taulukko, muut kokonaislukuja! int t1[], t2, t3[]; // t2 on kokonaisluku, muut taulukkoja! Dynaamiset vaihtoehdot String ja taulukko-olioiden kokoa ei voi muuttaa Huomaa myös vastaavat vaihtoehtoiset luokat alla, jotka ovat kooltaan dynaamisia: StringBuffer java.lang -pakkauksessa Vector java.util -pakkauksessa Dynaaminen taulukko Muista import-lause (java.util) 3.10.2000 E. Hyvönen: Java Osa 5 27 3.10.2000 E. Hyvönen: Java Osa 5 28 Kertausta Mikä eroja on merkkijonoilla ja merkkitaulukoilla? Kissa [] c = new Kissa[3]; // c[1] ==? int[] b = null; // Taulukon koko? Piirrä matriisi: int [][] m = {{1,2,3}, {4,5}} Mikä arvo: m[0][2], m[1][1], m[1][2]? Miten voit muuttaa 2-alkioisen taulukon 3- alkioiseksi? Omat tietorakenteet 3.10.2000 E. Hyvönen: Java Osa 5 29 5
Tietorakenteiden määrittely Linkitetty lista Luokkia voi käyttää tietueina. Näistä voi rakentaa mutkikkaampia tietorakenteita. Esimerkiksi sukupuu: class Henkilö { String nimi; Henkilö isä; Henkilö äiti; int ikä; } Käsitellään esimerkkinä linkitettyä listaa 3.10.2000 E. Hyvönen: Java Osa 5 31 Alkioiden muodostama "ketju" Jokainen alkio tietää seuraajansa (ehkä myös edeltäjänsä) Alkioiden lisääminen väliin ja poistaminen helppoa Alkio voi edustaa myös alilistaa Hierarkkiset rakenteet 3.10.2000 E. Hyvönen: Java Osa 5 32 Esimerkki (Wikla 4.3.4, s. 157) Lisätietoja Listojen käsittelyä Arto Wikla: Ohjelmoinnin perusteet Java-kielellä, OtaDATA, 1998. John Lewis, William Loftus: Java Software Solutions, Addison-Wesley, 1998. 3.10.2000 E. Hyvönen: Java Osa 5 33 3.10.2000 E. Hyvönen: Java Osa 5 34 6