1. Java–kielen taulukoista

 Taulukko se taasen tuttu

oiva säilö alkioille

maja muuttujalle monelle

silmäiltäväksi silmukalla.

 

Mitä tässä luvussa käsitellään?

·      Java–kielen taulukot

·      taulukoiden ja viitteiden yhteys

·      moniulotteiset taulukot

 

Syntaksi:

Taulukon esittely:    alkiontyyppi taulukonnimi[];

Taulukon luominen:    taulukonnimi = new alkiontyyppi[koko_alkioina]

Alkioon viittaaminen: taulukonnimi[alkion_indeksi]

Muista                1. indeksi = 0

                      viimeinen  = koko_alkiona-1

Silmukoissa           for (i=0; i<taulukonnimi.length; i++) ...

2-ul.taulukon es:     alkiontyyppi taulukonnimi[][];

2-ul taul. luominen:  taulukonnimi = new alkiontyyppi[riveja][sarakkeita]

 

Luvun esimerkkikoodit:

http://www.mit.jyu.fi/~vesal/kurssit/ohj2/moniste/esim/java-taul/

 

1.1 Yksiulotteiset taulukot

C–kielessä taulukoita ei oikeastaan ole, tai ainakin ne ovat '2. luokan kansalaisia'.  Lausuma tarkoittaa sitä, että taulukoista on käytettävissä vain 1. alkion osoite ja esimerkiksi taulukon sisällön sijoittaminen toiseen taulukkoon ei onnistu sijoitusoperaattorilla.  Lisäksi taulukon rajoissa pysymiselle ei ole minkäänlaista valvontaa.

Javassa onneksi taulukot on tehty hieman paremmin.  Erityisesti kriittisistä rajojen ylityksistä tulee poikkeus.

1.1.1 Taulukon määrittely

Taulukko määritellään kertomalla taulukon alkioiden tyyppi ja luomalla sitten varsinainen taulukko:

int k_pituudet[];         // saadaan vasta viite jolla voidaan viitata taulukkoon

kpituudet = new int[12];  // luodaan taulukko;

 

Tällöin taulukon 1. alkion indeksi on 0 ja 12. alkion indeksi on 11.

Määrittelyllä muuttujasta k_pituudet tulee osoitin kokonaislukuun; taulukon alkuun.

1.1.2 Taulukon alkioihin viittaaminen indeksillä

Taulukon alkioon voidaan viitata alkion indeksin avulla

k_pituudet[0]=31; /* tammikuu */

k_pituudet[1]=28; /* helmikuu */

 

k_pituudet[2]──┐

               │

k_pituudet     │

  │            v 

  │      0  1  2  3  4  5  6  7  8  9 10 11

  │    ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐

  └───>│31│28│31│30│31│30│31│31│30│31│30│31│

       └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘

 

Taulukon rajojen ylityksestä seuraa IndexOutOfBoundsException-poikkeus

k_pituudet[24]=31;

 

eli 2 paikkaa eteenpäin taulukon alusta lukien. 

Taulukko voitaisiin nollata seuraavalla silmukalla:

for (int i=0; i<k_pituudet.length; i++)

  k_pituudet[i]=0;

 

Huomautus!  Taulukoiden käsittelyssä on muistettava, että indeksi liikkuu välillä [0,YLÄRAJA[.

1.1.3 Taulukon alustaminen

Taulukko voidaan alustaa (vain) esittelyn yhteydessä:

                /*  1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12 */

int k_pituudet[] = {31,28,31,30,31,30,31,31,30,31,30,31};

 

Tehtävä 13.1  Taulukon alkioiden summa

Kirjoita funktio–aliohjelma taulukon_summa, joka palauttaa taulukon alkioiden summan.  Kirjoita pääohjelma, jossa aliohjelmaa kutsutaan valmiiksi alustetulla taulukolla k_pituudet ja tulostetaan vuoden päivien lukumäärä.

 

1.2 Merkkijonot

Merkkijonot ovat eräs ohjelmoinnin tärkeimmistä tietorakanteista.  Valitettavasti tämä on lähes poikkeuksetta unohtunut ohjelmointikielten tekijöiltä.  Heille riittää että kielellä VOI tehdä merkkijonotyypin.  Tavallista käyttäjää kiinnostaa tietysti onko se tehty ja onko se hyvä.  Usein vastaus on EI.  Näin myös C–kielen kohdalla!  C++:han on jo välttävä merkkijonoluokka.  Javassa on kaksi merkkijonoluokkaa String ja StringBuffer.

1.2.1 Merkkityyppi

Yksittäinen merkki on Java–kielessä tyyppiä char:

char rek_1_merkki;

rek_1_merkki = 'X';

 

Merkkimuuttujiin voidaan vallan hyvin sijoittaa myös merkin koodiarvo

char m;

m = 65;

if ( m == 'A' ) ...

Lukuarvo tarkoittaa merkin (UNICODE–) koodia. 

1.2.2 String

Javan String-luokka tarjoaa muuttumattoman merkkijonon (immutable).  Merkkijonon "sisältö" voidaan vaihtaa vain luomalla uusi merkkijono.

1.2.3 StringBuffer

Jos halutaan merkkijono, jonka sisältöä voidaan muuttaa (mutable), pitää käyttää StringBuffer-luokkaa.

1.3 Moniulotteiset taulukot

Moniulotteiset taulukot ovat Javassa vain yksiulotteisia taulukoita taulukoista.

1.3.1 Kiinteä esittely

Kaikkein helpoin tapa esitellä moniulotteinen taulukko on aivan normaali esittely:

int matriisi[][] = new int[3][4]

              ┌───┬───┬───┬───┐

matriisi[0]──>│   │   │   │   │─── matriisi[0][3]

              ├───┼───┼───┼───┤

matriisi[1]──>│   │   │   │   │

              ├───┼───┼───┼───┤

matriisi[2]──>│   │   │   │   │

              └───┴───┴───┴───┘

 

Taulukon nimi on vain viite taulukkoon.  Taulukko on yksiulotteinen taulukko riveistä.  Edellä

matriisi.length == 3

matriisi[1].length == 4

 

Taulukon alkioina voi tietysti olla mikä tahansa olemassa oleva tyyppi.    Myös moniulotteinen taulukko voidaan alustaa esittelyn yhteydessä:

double yks[][] = {

  { 1.0, 0.0, 0.0 },

  { 0.0, 1.0, 0.0 },

  { 0.0, 0.0, 1.0 }

}

 

Tehtävä 13.2  Matriisit

Kirjoita seuraavat aliohjelmat, jotka saavat parametrinään 2 nxn matriisia ja palauttavat nxn matriisin:

1.        Laskee yhteen 2 matriisia.

2.        Kertoo kaksi matriisia keskenään.  (Kirjoita avuksi funktio, joka kertoo matriisin  rivin i toisen matriisin sarakkeella j).

 

1.3.2 Yksiulotteisen taulukon käyttäminen moniulotteisena

Toisaalta moniulotteinenkin taulukko voidaan toteuttaa 1–ulotteisena.  Tästä muunnoksestahan puhuttiin jo monisteen alkuosassa.  On makuasia kumpiko järjestys esimerkiksi matriisissa valitaan: sarakelista vaiko rivilista.  Rivilista on C–kielen mukainen, mutta toisaalta maailma on pullollaan Fortran aliohjelmia, joissa matriisit on talletettu sarakelistana.  Siis kumpikin tapa on syytä hallita.

Tehtävä 13.3  Matriisi 1–ulotteisena

Kirjoita aliohjelma tee_yksikko, jolle tuodaan parametrinä neliömatriisin rivien lukumäärä ja 1–ulotteisen taulukon viite, ja joka alustaa tämän neliömatriisin yksikkömatriisiksi.

 

1.3.3 Taulukko taulukoista

Javassahan moniuloitteinen taulukko on tosiasiassa taulukko taulukoista.

java-taul\Mat2.c - matriisi parametrina riviosoittimen avulla

/**

 * Matriisi parametrina

 * @author Vesa Lappalainen

 * @version 1.0, 04.03.2003

 */

public class Mat2 {

 

  public static double alkioiden_summa(double mat[][]) {

    double summa = 0; int riv = mat.length;

    for (int i=0; i<riv; i++) {

      int sar = mat[i].length;

      for (int j=0; j<sar; j++)

        summa += mat[i][j];

    }

    return summa;

  }

 

  public static void main(String[] args) {

    double s1,s2,s3;

    double yks[][] = {

      { 1.0, 0.0, 0.0 },

      { 0.0, 1.0, 0.0 },

      { 0.0, 0.0, 1.0 }

    };

    double mat2[][] = { {1,2,3,4},{5,6,7,8} },

           mat3[][] = { {1,0,0},{0,1,0},{0,0,1} };

    s1 = alkioiden_summa(yks);

    s2 = alkioiden_summa(mat2);

    s3 = alkioiden_summa(mat3);

    System.out.println("Summat ovat " + s1 + ", " + s2 + " ja " + s3);

  }

}

 

1.3.4 Taulukko viitteistä

Se että matriisi onkin vain taulukko viitteistä riveihin, mahdollistaa edellä olleen mielivaltaisen kokoisen matriisin käyttämisen aliohjelman parametrina.  Matriisin rivit voidaan luoda myös erikseen:

mat─┐      mat[0]         ┌────────── mat[0][2]

    │      │              │     

    │      │              

    v      └───>┌───┬───┬───┬───┐

  ┌───┐   ┌────>│ 1 │ 2 │ 3 │ 4 │  r0

0 │ o─┼───┘     └───┴───┴───┴───┘

  ├───┤         ┌───┬───┬───┬───┐

1 │ o─┼────────>│ 5 │ 6 │ 7 │ 8 │  r1

  ├───┤         └───┴───┴───┴───┘

2 │ o─┼───┐     ┌───┬───┬───┬───┐

  └───┘   └────>│ 9 │ 0 │ 1 │ 2 │  r2

                └───┴───┴───┴───┘

 

java-taul\Mat3.java - matriisi osoitintaulukon avulla

/**

 * Matriisi kasattuna irrallisista riveistä

 * @author Vesa Lappalainen

 * @version 1.0, 04.03.2003

 */

public class Mat3 {

 

  public static double alkioiden_summa(double mat[][],int riveja, int sarakkeita) {

    int riv = Math.min(riveja,mat.length);

    double summa = 0;

    for (int i=0; i<riv; i++) {

      int sar = Math.min(sarakkeita,mat[i].length);

      for (int j=0; j<sar; j++)

        summa += mat[i][j];

    }

    return summa;

  }

 

  public static void main(String[] args) {

    double s1,s2;

    double r0[] = {1,2,3,4}, r1[] = {5,6,7,8}, r2[] = {9,0,1,2};

    double mat[][] = {r0,r1,r2};

    s1 = alkioiden_summa(mat,2,3);

    s2 = alkioiden_summa(mat,3,4);

    System.out.println("Summat on " + s1 + " ja " + s2);

 

  }

}

 

Javan menettelyssä on vielä se etu, ettei kaikkien rivien välttämättä tarvitsisi edes olla yhtä pitkiä.  Harvassa matriisissa osa osoittimista voisi olla jopa null–osoittimia, mikäli rivillä ei ole alkioita (aliohjelman pitäisi tietysti tarkistaa tämä).  Oikeasti rivit usein vielä luotaisiin dynaamisesti ajonaikana tarvittavan pituisina.

Tehtävä 13.4  Transpoosi

Kirjoita taulukko–osoittimia käyttäen aliohjelma, joka saa parametrinään kaksi matriisia ja niiden dimensiot.  Aliohjelma tarkistaa voiko toiseen matriisiin tehdä toisen transpoosin (vaihtaa rivit ja sarakkeet keskenään) ja tekee transpoosin jos pystyy.  Onnistuminen palautetaan aliohjelman nimessä.

 

1.4 Komentorivin parametrit (argv)

Esimerkiksi Java–kielinen pääohjelma saa käyttöjärjestelmältä tällaisen taulukon kutsussa olleista argumenteista:

java-taul\Argv.java - komentorivin parametrit

/**

 * Ohjelma tulostaa komentorivin parametrit

 * @author Vesa Lappalainen

 * @version 1.0, 04.03.2003

 */

public class Argv {

  public static void main(String[] args) {

    System.out.println("Argumenttejä on " + args.length + " kappaletta:");

    for (int i=0; i<args.length; i++)

      System.out.println(i + ": " + args[i]);

  }

}

 

Kun ohjelma ajettaisiin komentoriviltä saattaisi tulostus olla seuraavan näköinen (MS–DOS -koneessa):

C:\kurssit\moniste\esim\java-taul>java Argv kissa istuu puussa[RET]

Argumentteja on 3 kappaletta:

0: kissa

1: istuu

2: puussa

C:\kurssit\moniste\esim\java-taul>_

                                                       

argvs┐             ┌───┬───┬───┬───┬───┬

     │   ┌────────>│ k │ i │ s │ s │ a │

     v   │         └───┴───┴───┴───┴───┴

   ┌───┐ │         ┌───┬───┬───┬───┬───┐   

0  │ o─┼─┘ ┌──────>│ i │ s │ t │ u │ u │     

   ├───┤   │       └───┴───┴───┴───┴───┘

1  │ o─┼───┘       ┌───┬───┬───┬───┬───┬───┐

   ├───┤     ┌────>│ p │ u │ u │ s │ s │ a │

2  │ o─┼─────┘     └───┴───┴───┴───┴───┴───┘   

   └───┘

       

 

Tehtävä 13.5  Palindromi

Kirjoita Java-ohjelma Pali, jota kutsutaan komentoriviltä seuraavasti:

 

C:\OMAT\OHJELMOI\VESA>java Pali kissa[RET]

kissa EI ole palindromi!

C:\OMAT\OHJELMOI\VESA>java Pali saippuakauppias[RET]

saippuakauppias ON palindromi!

C:\OMAT\OHJELMOI\VESA>_