Ilkka Koivistoinen 13.02.2002

Edellinen

7 Taulukot

Taulukko on jono samaa tietotyyppiä tai olioita olevia muistipaikkoja. Esimerkiksi edellä ollut char merkkijono[] = new char[20]; on 20 kertaa yhden merkin pituinen muistialue, jonka paikkoihin viitataan indeksin i avulla esimerkiksi merkkijono[i-1]. Ensimmäinen taulukon muistipaikka on paikassa merkkijono[0], toinen paikassa merkkijono[1] jne.

int luvut[] = new int[200] varaa muistia 200 int –tyypin verran (siis 200 * 32 bittiä).

Seuraavassa esimerkissä on tehty 5 kokonaisluvun taulukko ja tulostettu se.

Esimerkki 23.

    import Lue;
    public class E23
    {
       public static void main (String args[])
       {
           int[] taulu = {3,2,5,6,3};
           System.out.println("taulu[1] = " + taulu [1]);
           System.out.println("taulu[2] = " + taulu [2]);
           System.out.println("taulu[3] = " + taulu [3]);
           System.out.println("taulu[4] = " + taulu [4]);
           System.out.println("taulu[5] = " + taulu [5]);

           // ja sitten sama for –silmukalla
           int i;
           for (i = 1; i <= 5; i++)
              System.out.println("taulu["+i+"] = " + taulu [i]);
       }
    }

Saitko virheilmoituksen java.lang.ArrayIndexOutOfBoundsException? Tämä aiheutui siitä, että yritit tulostaa muistipaikkaa taulu[5]. Kuitenkin 5:s muistipaikka on taulu[4]:ssä. Tämä johtuu siitä, että java aloittaa indeksoinnin aina 0:sta. Korjaa edellistä ohjelmaa siten, että indeksit ovat 0,..,4. Java siis tarkistaa ajoaikaiset taulukon indeksit. (  for (i = 0; i < 5; i++)  )

taulu[0] taulu[1] taulu[2] taulu[3] taulu[4]

Eräs tapa välttää sekaannus muistin käytössä on käyttää length -muuttujaa, joka ilmoittaa taulukon pituuden eli talletettujen numeroiden määrän taulukossa. Esimerkiksi for -silmukka voidaan toteuttaa seuraavasti

int taulu = new int[100];
for (int i=0;i<taulu.length;i++) …;  // taulu.length on nyt 5

Tällöin silmukkaindeksin karkaaminen yli viimeisen arvon on mahdotonta.

Esimerkki 24.

Tehdään kaksiulotteinen taulukko

    import Lue;

    public class E24
    {
       public static void main (String args[])
       {
            int[] taulu;
            int i,j;
            taulu = new int [10];
            for (i=0; i<taulu.length; i++)
                taulu[i] = i+1;

            // kaksiulotteinen taulukko
            int[][] matriisi=new int[10][10];
            for ( i=0; i<taulu.length; i++)
                for ( j=0; j<taulu[i].length; j++)
                    matriisi[i][j] = j+i+1;

            // tulostus
            for (i=0; i<taulu.length ;i++)
                System.out.print(taulu[i]+" ");
            System.out.println("\n");

            for (i=0; i<taulu.length ;i++)
            {
                 for (j=0; j<taulu[i].length; j++)
                     System.out.print(matriisi[i][j]+" ");
                 System.out.println();
            }
       }
    }

Java ei suoraan tue moniulotteisia taulukoita, mutta ne luodaan taulukkona, jonka alkiona on taulukko. Tätä voidaan jatkaa vaikka kuinka moneen sisäkkäiseen indeksiin asti. Edellisessä esimerkissä oli kaksinkertainen silmukka. Tutki tarkkaan, että ymmärrät sen toimintaperiaatteen.

Esimerkki 25.

Tähtikolmio

    public class E25
    {
       public static void main (String args[])
       {
            int max = 10;
            String[] merkkijonot=new String[max];
            int i,j;

            // Tehdään tähtikolmio
            for (j=0; j<max; j++)    //   j < merkkijonot.length olisi parempi
            {
                for (i=0; i<=j; i++)
                    System.out.print("*");
                System.out.println();
            }

            // Tehdään kirjaintaulukko
            for (i=0; i<max; i++)
                merkkijonot[i] = "abcdefghij";
            for (i=0; i<max; i++)
                System.out.println(merkkijonot[i]);

            // Tehdään kirjainkolmio
            for (i=0 ; i<max ; i++)
            {
                for (j=0; j<i; j++)
                    System.out.print(merkkijonot[i].charAt(j));
                System.out.println();
            }
       }
    }

{Jos olet opetellut esim. pascalia, niin lue seuraava: Taulukkoja käsiteltäessä indeksin alkaminen 0:sta tuottaa usein paljon hankaluuksia. Tämän voi aina kiertää määrittelemällä taulukon todelliseksi kooksi yhtä suurempi, mitä tarvitaan ja jättämällä 0:s rivi tai sarake käsittelemättä.]

Silmukkarakenteiden yhteydessä taulukot ovat mitä parhain mahdollinen talletusmuoto ja seuraavissa esimerkeissä on yritetty havainnollistaa niiden käyttöä silmukkarakenteiden kanssa.

Esimerkki E26

    import Lue;
    public class E26 // Tarkista laskimella, että ohjelmasi laskee oikein!!!
    // Luetaan näppäimistöltä n lukua ja lasketaan niiden keskiarvo ja keskihajonta
    {
       public static void main (String args[])
       {
            int n;
            System.out.println("Monenko luvun keskiarvo lasketaan");
            n=Lue.kluku();
            while (n<0 || n>100)
            {
                System.out.println("Lukujen määrän pitäisi olla välissä 0 - 100. Anna uudestaan");
                System.out.println("Monenko luvun keskiarvo lasketaan");
                n=Lue.kluku();
            }
            int i, j, max = n;    // max määrittää taulukon pituuden
            double[] luvut=new double[max]; //
            double summa, karvo,khajonta;
            for (i=0; i<max; i++)
            {
                System.out.print("Anna "+i+".s luku ");
                luvut[i]=Lue.dluku();
            }
            summa = 0.0D;

            //keskiarvo
            for (i=0; i<max; i++)
                summa=summa+luvut[i];
            karvo=summa/max;

            //keskihajonta
            summa=0.0D;
            for (i=0; i<max; i++)
                summa=summa+Math.pow(karvo-luvut[i],2); //pow(x,2) on x toiseen
            khajonta=Math.sqrt(summa/max); //neliöjuuri

            //Tulostus
            System.out.println("Tulos:\nLukujen");
            for(i=0;i<max;i++)System.out.print(luvut[i]+" ");System.out.println();
            System.out.println("tunnusluvut ovat:\nLukuja: "+max+"\nKeskiarvo on : "+karvo +
            "\nKeskihajonta : "+khajonta);
       }
    }

Esimerkki 27.

    import Lue;
    public class E27
    // Luetaan näppäimistöltä n lukua ja tulostetaan niistä suurin
    {
       public static void main (String args[])
       {
            int n;
            System.out.println("Montako lukua annat");
            n=Lue.kluku();
            while (n<0 || n>100)
            {
                 System.out.println("Lukujen määrän pitäisi olla välissä 0 - 100. Anna uudestaan");
                 System.out.println("Montako lukua annat");
                 n=Lue.kluku();
            }
            int max,i;
            int[] luvut = new int[n];
            for (i=0; i<n; i++)
            {
                System.out.print("Anna "+(i+1)+".s luku ");
                luvut[i]=Lue.kluku();
            }
            max=-10000; // Laita tilalle -maxinteger, kun saat sen selville
    // toinen parempi ratkaisu on asettaa max = luvut[0]: ja kelata taulukko läpi toisesta alkiosta alkaen
            for (i=0; i<n; i++)
                if (luvut[i]>max)
                    max=luvut[i];
            //Tulostus
            System.out.println("Tulos:\nLuvuista");

            for(i=0;i<n;i++)
                System.out.print(luvut[i]+" ");
            System.out.println();
            System.out.println("suurin on "+max);
       }
    }

Esimerkki 28.

    import java.util.Random; // satunnaislukuja varten
    import Lue;
    public class E28 // Arvotaan 1000 kokonaislukua ja tulostetaan ne
    {
       public static void main (String args[])
       {
            Random SatunnaisLuku = new Random(); // Tyyppiä random oleva satunnaislukugeneraattori
            int i,j,tmp,n=1000;
            int[] taulukko=new int[n];
            for (i=0; i<n; i++)
                /*
                  SatunnaisLuku.nextDouble() palauttaa double-tyyppisen luvun välillä [0,1[. Huomaa, että 1 ei kuulu
                  tähän väliin.
                  SatunnaisLuku.nextDouble()*n antaa arvoksi double-luvun välillä 0 <= x < n
                  ja (int) ottaa siitä kokonaisosan (pyöristys vai katkaisu?)

                */
                taulukko[i] = (int) (SatunnaisLuku.nextDouble()*n);//satunnainen kokonaisluku välilllä 0 <= x < n
            //Tulostus
            System.out.println("Tulos\nSatunnaisluvut ovat");
            for (i=0; i<n; i++)
                System.out.print(taulukko[i]+" ");
            System.out.println()
       }
    }

Esimerkki 30.

Kuplalajittelualgoritmi. Esimerkki sisäkkäisistä silmukoista

import java.util.Random; // satunnaislukuja varten
import Lue;
public class E29
// Arvotaan 1000 kokonaislukua ja tulostetaan ne lajiteltuna
{
   public static void main (String args[])
   {
        Random SatunnaisLuku = new Random(); // Tyyppiä random oleva satunnaisluku
        int i,j,k,tmp,n=1000;
        int[] taulukko=new int[n];
        for (i=0; i<n; i++)
            taulukko[i] = (int) (SatunnaisLuku.nextDouble()*n);//satunnainen kokonaisluku välilllä 0 <= x < n

        //Tulostus
        System.out.println("Tulos\nSatunnaisluvut ovat");
        for(i=0; i<n; i++)
            System.out.print(taulukko[i]+" ");
        System.out.println();

        //Lajittelu
        for (i=0; i<n-1; i++)
        {
            k=i;
            for (j=i+1 ; j<n ; j++)
                 if (taulukko[j]>taulukko[k])
                    k=j;

            // Suoritetaan vaihto jos tarpeellista
            if (i != k)
            {
                tmp=taulukko[i];
                taulukko[i]=taulukko[k];
                taulukko[k]=tmp;
            }
        }

        //Tulostus lajittelun jälkeen
        System.out.println("Tulos\nSatunnaisluvut ovat lajiteltuna");
        for (i=0; i<n; i++)
            System.out.print(taulukko[i]+" ");
        System.out.println();
   }
}

Käy lajittelualgoritmi huollella läpi. Sen idea on jakaa lukujono kahtia alku ja loppuosaan, missä alun k alkiota ovat järjestyksestä ja loppuosan k+1,..,n alkioista haetaan suurin, joka vaihdetaan k+1:n alkion kanssa. Lisää arvottavien lukujen määrää ensin 10000 ja sitten 100000 jne. Jätä tulostus pois kunhan olet varmistunut, että ohjelma toimii ja testaa. Kuinka nopea koneesi java –tulkilla oikeastaan onkaan?

Taulukon alkioiden poisto ja lisäys on käsitelty olio-ohjelmoinnin kurssin esimerkissä 40.

Seuraavassa on tehtäviä, jotka lähtevät helpommista ja päätyvät varsin hankaliin ohjelmointitehtäviin. Jätä väliin ne tehtävät, joissa et ymmärrä matemaattista kontekstiä, ne on tarkoitettu laajan matematiikan pitemmälle ehtineille opiskelijoille.

7.1 Tehtäviä

  1. Tee ohjelma, joka piirtää tähdistä onton neliön, kun neliön sivun tähtien määrä luetaan näppäimistöltä.
  2. * Tee ohjelma, joka lukee merkkijonon nappaimistöltä ja vaihtaa kaksi vierekkaista merkkiä keskenään. Esimerkiksi jono "esimerkki1" muutuisi jonoksi "semirekk1i". Jos merkkejä on pariton määrä, ei viimeiselle merkille tehdä mitöään.
  3. * Tee ohjelma, joka laskee todistuksesi numeroiden keskiarvon.
  4. Laadi opetusohjelma, joka opettaa englanninkielen lukusanat yhdestä kymmeneen. Jokaisen sanaa saa yrittää korkeintaan kolmasti.
  5. *. Laadi ohjelma, joka arpoo n luku (n kysytään näppäimistöltä), luettelee luvut ja ilmoittaa niistä suurimman ja pienimmän.
  6. * Tee ohjelma, joka kyselee kuukauden jokaisen päivän lämpötilat ja laskee lämpötilajakauman tunnusluvut n, x, ja sn.
  7. Tee ohjelma. joka arpoo sata satunnaislukua kahteen taulukkoon a ja b sekä laskee niiden alkioiden erotuksen neliöt taulukkoon c (ts. c[i]=(a[i]-b[i])2 ). Tämän jälkeen lasketaan taulukon luvuista c keskiarvo ja hajonta. Toista lasku 10 kertaa ja vertaa keskiarvoja ja hajontalukuja toisiinsa. (Tee tämä joko paperilla ja kynällä tai ohjelmoimalla.)
  8. Tee ohjelma, joka laskee käyrän y=e-x*x ja x-akselin väliin jäävän pinta-alan likimääräisen lausekkeen suorakaiteina (Riemannin yläsummana, kun pylvään leveys on äärellinen luku), kun näppäimistöltä kysytään alueen alku- ja loppupisteet sekä pylvään leveys.
  9. Tee ohjelma, joka laskee kahden komiulotteisen vektorin välisen pistetulon, kun vektorien skalaarikomponentit luetaan näppäimistöltä Aseta vektorien skalaarikomponentit 3:n alkion pituisiin taulukoihin ja  tee lasku näillä taulukoilla. Yleistä n -uloitteisen avaruuden vektoreille. (Asiaa ei ole enää helppo hahmottaa, mutta kon elaskee kiltisti)
  10. Tee ohjelma, joka laskee kahden vektorin välisen pistetulon, kun vektorien pituudet on annettu ja kulma saa muuttua koko kierroksen sopivin välein. Lue näppäimistöltä pituudet ja kulmanmuutosaskel. Laita tulokset taulukkoon ja listaa ne siistiin muotoon.
  11. * Tutki ohjelmoimalla mikä x-akselin piste on lähinnä paraabelia y=x2+100x+876. Vertaa tulosta analyyttisesti laskettuun.
  12. * Tee ohjelma, joka ratkaisee sopivan neljännen asteen polynomin nollakohdan, puolitusmenetelmällä, kun aloitusväli annetaan. Näppäimistöltä kysytään myös tuloksen tarkkuus.
  13. * Toista edellinen tehtävä Newtonin menetelmällä.
  14. Tee parannettu kuplalajittelualgoritmi, jossa lajittelu lähtee taulukon molemmista päistä. (Isot luvut oikealle, pienet vasemmalle)
  15. Tee ohjelma, joka arpoo lottokupongin 12 sarakkeen 7 numeroa, oikean rivin ja lopuksi tarkastaa tuloksen ja ilmoittaa oikeiden arvausten määrän. Tulosta luvut aina tarvittaessa.
  16. * Tee ohjelma, joka laskee ja tulostaa Pascalin kolmion iteraatiokaavalla , kun n ja k luetaan näppäimistöltä

Vastaukset

Ilkka Koivistoinen 13.02.2002

Edellinen