Enrera
Mòdul 3
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Matrius
   
 

Com molts d'altres llenguatges de programació, Java permet organitzar alguns conjunts de dades en matrius (arrays). Una matriu consisteix en una col·lecció de variables del mateix tipus que tenen un nom comú. Hom pot accedir a un element específic d'una matriu mitjançant una altra variable que actua com a índex.

El tractament de les matrius a Java és semblant al que en fa C, però no exactament igual; les diferències principals apareixen a partir del fet que, a Java, totes les variables es gestionen per referència i no per valor. En conseqüència, potser no és veritat que a Java no hi hagi apuntadors, sinó que més aviat, tot el que veiem i manipulem al codi són en realitat apuntadors!

   
Matrius (arrays):
   
Atenció !

Començarem per les matrius unidimensionals:

  • Nom: Per a donar nom a una variable que sigui una matriu unidimensional se segueixen les mateixes convencions que en el cas de variables no matricials. (vegeu la pràctica 2 del mòdul 2).

  • Declaració: Per declarar una variable que sigui una matriu unidimensional es fa el mateix que en el cas de variables no matricials (consulteu altra vegada la pràctica 2 del mòdul 2), però ara, el nom del tipus ha d'anar seguit per l'operador "[]":

    int[] aNombres;            // "aNombres" declarada com a matriu
                               // unidimensional de nombres del
                               // tipus "int"

    String[] aTextos,aSermons; // "aTextos" i "aSermons" declarades
                               // com a matrius de variables del
                               // tipus "String"

    int nm; // "mn", no matricial, declarada com a nombre del tipus
            // "int"

  • Inicialització: Ja s'entén que amb la sola declaració, el compilador no té prou informació com per a reservar espai de memòria a la matriu només declarada, a diferència del que passa amb la declaració de variables no matricials. El compilador ha de saber (i nosaltres li ho hem de dir mitjançant el nostre codi!) quants espais del tipus ha de reservar, és a dir, quina és la longitud de la matriu. Això pot fer-se de dues maneres:

    • Inicialitzar la matriu sense omplir-la amb els valors que hagi de contenir. Així:

      int[] aNombres; 
      aNombres=new int[12]; // Es crea una matriu unidimensional
                            // de longitud 12. Es creen els dotze
                            // espais i s'omplen amb el valor
                            // "null"


      o bé així:

      int[] aNombres=new int[12]; // Es declara i es crea una
                                  // matriu unidimensional de
                                  // longitud 12. Es creen els
                                  // dotze espais i s'omplen amb
                                  // el valor "null"


    • Inicialitzar la matriu omplint-la amb els valors que hagi de contenir. Així:

      int[] aNombres={2,0,0,3}; // Es declara i es crea una
                                // matriu unidimensional de
                                // longitud 4. Es creen els
                                // quatre espais i s'omplen,
                                // respectivament, amb els
                                // el valors 2, 0, 0 i 3.


      Només per a matrius curtes! ;)

    Naturalment, les línies de codi

    int[] aNombres=new int[4];

    i

    int[] aNombres={null,null,null,null};

    són completament equivalents.

  • Referència als seus elements: La variable d'índex d'una matriu ha de prendre valors enters no negatius: el primer element de la matriu té, doncs, índex 0. La sintaxi és aquesta:

    String sDies={"Dilluns","Dimarts",
                  "Dimecres","Dijous",
                  "Divendres","Dissabte",
                  "Diumenge"};
    System.out.println(sDies[0]); // S'imprimirà "Dilluns"
    System.out.println(sDies[5]); // S'imprimirà "Dissabte"
    System.out.println(sDies[6]); // S'imprimirà "Diumenge"
    System.out.println(sDies[7]); // Es tirarà una excepció
                                  // ArrayIndexOutOfBoundsException
                                  // perquè ens hem passat de la
                                  // longitud de la matriu.

    Atenció!: Passar-se dels límits d'una matriu, és a dir, cridar-ne un element més enllà del seu límit superior i, per tant, inexistent, és un error de temps d'execució i, per tant, el compilador no el detecta. A diferència de C però, la Màquina Virtual té la delicadesa d'avisar-nos-en en temps d'execució, tot explicant-nos què ha passat mitjançant una instància de l'excepció java.lang.ArrayIndexOutOfBoundsException.

  • Pas de matrius com a arguments a mètodes: es fa simplement amb el nom. Per declarar matrius com a arguments de mètodes cal fer el mateix que quan es declaren com a variables: el nom del tipus amb l'operador "[]".  El següent programa (Projecte ComEsDiuEnCastella "Empty Project", fitxer ComEsDiuEnCastella.java) mostra això:

    class ComEsDiuEnCastella {

        static final String EL="El ";
        static final String EN_CASTELLA=" en castella es diu ";

        public static void main (String[] args) {
            String[] sDiesCat={"Dilluns","Dimarts","Dimecres",
                               "Dijous","Divendres","Dissabte",
                               "Diumenge"};
            String[] sDiesCast={"Lunes","Martes","Miercoles",
                                "Jueves","Viernes","Sabado",
                                "Domingo"};
                for (int i=0;i<7;i++) {
                    printDia(sDiesCat,sDiesCast,i); // Encara que
                                                    // "sDiesCat" i
                                                    // "sDiesCast"
                                                    // siguin
                                                    // matrius, es
                                                    // passen com a
                                                    // paràmetres al
                                                    // mètode
                                                    // "printDia"
                                                    // simplement
                                                    // amb el seu
                                                    // nom.

                }
        }

    /**
    * Com que els paràmetres "sCat" i "sCast" són matrius del tipus
    * "String", a la definició del mètode el tipus s'expressa
    * mitjançant "String[]".
    */

        static void printDia (String[] sCat,String[] sCast,int nD) {
            System.out.println(EL+sCat[nD]+EN_CASTELLA+sCast[nD]);
        }

    }


  • si volem conèixer la longitud d'una matriu, és a dir, el nombre d'elements que conté (per exemple, la matriu de strings que el mètode main llegeix de la cònsola: observeu-ne la sintaxi: main(String[] args)) es fa servir el camp (field) length:

    String[] sDies={"Dilluns","Dimarts","Dimecres","Dijous",
                    "Divendres","Dissabte","Diumenge"};

    System.out.println(sDies.length); // S'imprimirà "7", que és
                                         // la longitud de "sDies"

  • Encara que les cadenes de text (strings) són també matrius, a diferència d'allò que passa al llenguatge C, quasi podem oblidar-nos d'això perquè la classe java.lang.String ja conté els mètodes necessaris per tractar-les amb comoditat.
   
  Matrius bi- i multidimensionals:
   
Atenció ! Una matriu multidimensional no és res més que una matriu de matrius. Hom no sol anar més enllà de les de dues dimensions a causa de la gran quantitat de memòria que poden arribar a ocupar: una matriu matriu[p][q][r] ocupa p*q*r posicions de memòria!

Vegem-ne les principals qüestions per a usar-les:

int[][] sumes_1; // Declaració de "sumes_1" com a matriu
                 // bidimensional. No se li reserva cap espai
                 // a la memòria.

nombre=new int[3][5]; // Es reserven 3 x 5 = 15 espais de memoria
                      // del tipus "int".

    for (int i=0;i<3;i++) { // S'omple la matriu amb les sumes i+j
            for (int j=0;j<5;j++) {
                int[i][j]=i+j;
            }
    }

int[][] sumes_2={{0,1,2,3,4},   // Declaració de "sumes_2" com a
                 {1,2,3,4,5},   // matriu bidimensional i atribució
                 {2,3,4,5,6}};  // de valors.

  • Declaració: El nom del tipus seguit de tantes vegades l'operador "[]" com indiqui la dimensió de la matriu a declarar.

  • Inicialització: Es pot fer de dues maneres:

    • Per atribució directa d'uns valors inicials als seus elements, tal com es fa per a la matriu "sumes_2" de l'exemple anterior.

    • Per ús de l'operador new, amb especificació de la longitud de la matriu unidimensional principal i de totes les altres submatrius, tal com es fa per a la matriu "sumes_1" de l'exemple anterior. Els elements queden amb el valor null i cal introduir-ne els valors després.

  • Crida als elements: Podem accedir a submatrius, subsubmatrius, etc. fins arribar als elements individuals mitjançant l'aplicació repetida de l'operador "[index]": matriu[3], matriu[3][2], matriu[3][2][5], etc. Atenció: de la mateixa manera que a C, i a diferència d'altres llenguatges, matriu[3,2] és incorrecte!

  • Es pot demanar la variable length per a la matriu sencera i per a cadascuna de les submatrius. A l'exemple anterior, sumes_1.length torna 3 i sumes_1[0].length, sumes_1[1].length i sumes_1[2].length tornen 5
Només cal afegir que les matrius sumes_1 i sumes_2 de l'exemple contenen exactament els mateixos elements situats a les mateixes posicions.
   
  Què es pot fer amb una matriu?
   
Pràctica
  • Per exemple podem preguntar-nos si un cert element és o no és a una matriu. El codi següent (Projecte Musics "Empty Project", fitxer Musics.java) ens diu si un nom (una cadena o string) és a una matriu (String[] musics) o no i, en cas afirmatiu, ens informa de la seva posició a la matriu:

    class Musics {

    /**
    * Llista de noms de músics com a matriu de strings:
    *
    */

        static String[] musics={"Monteverdi","Vivaldi","Haendel",
                                "Bach","Haydn","Mozart","Beethoven",
                                "Schubert","Mendelssohn","Grieg",
                                "Schumann","Chopin","Listz",
                                "Brahms","Wagner","Berlioz",
                                "Debussy","Strauss","Schoenberg",
                                "Berg"};

        public static void main (String[] args) {
            int quants=musics.length;// Longitud de la matriu dels
                                     // paràmetres que dóna l'usuari

                if (args.length>0) { // S'han donat paràmetres
                    String nom=args[0]; // El primer dels paràmetres
                    int aOn=-1; // De moment, no s'ha trobat
                        for (int i=0;i<quants;i++) { // Recorrem
                                                     // la matriu
                                                     // de manera
                                                     // seqüencial
                                                     //

                            String aquestMusic=musics[i];// Nom per
                                                         // comparar

                                if (nom.equals(aquestMusic)) {// Si?
                                    aOn=i; // Posició on ha estat
                                           // trobat

                                    break; // No cal seguir buscant:
                                           // trenquem el cicle.

                                }
                        }
                        if (aOn<0) { // No hi era
                            System.out.println("El compositor "+
                            nom+
                            " no es a la llista");
                        } else { // Hi era
                            System.out.println("El compositor "+
                            nom+
                            " es al lloc "+
                            aOn+
                            " de la matriu");
                        }
                } else { // No s'han donat paràmetres
                    System.out.println("No em dius cap nom :(");
                }
        }

    }


    L'ús, des de la línia de comanaments (finestra de MSDOS, etc.), és aquest:
   
Pràctica
  • Podem, també, ordenar-ne els elements. A l'aplicació següent (Projecte QSort "Empty Project", fitxer QSort.java):

    class QSort {

        public static void main (String[] args) {
            int quants=args.length; // Quants nombres ha entrat
                                    // l'usuari com a paràmetres?

            int[] nombres=new int[quants]; // Declaració de la
                                           // matriu que ha de
                                           // contenir els nombres
                                           // a ordenar.

                for (int i=0;i<quants;i++) { // Com que main llegeix
                                             // els paràmetres
                                             // com a cadenes
                                             // (strings) cal
                                             // convertir-los a
                                             // nombres enters (int)

                    nombres[i]=Integer.parseInt(args[i]);
                }
            quickSort(nombres,0,quants-1);// Ordenació dels "quants"
                                          // elements de la matriu
                                          // "nombres", des de
                                          // la posició inicial, 0,
                                          // a la posició final,
                                          // "quants-1".

            printMatriu(nombres);// Impressió de la matriu "nombres"
        }

        static void printMatriu (int[] matriu) { // Mètode per a
                                                 // imprimir matrius

            System.out.println("Resultat:");
            int n=matriu.length;
                for (int i=0;i<n;i++) {
                    System.out.print (matriu[i]+" ");
                }
            System.out.println("\n-----");
        }

        static void quickSort (int[] matriu,   // Algorisme
                               int posInici,   // Quick Sort per a
                               int posFinal) { // ordenar els
                                               // elements de la
                                               // matriu "matriu"
                                               // des de la posició
                                               // "posInici" a la
                                               // posició "posFinal"

                if (posInici>=posFinal) { // Si hi ha menys de dos
                                          // elements per ordenar,
                                          // ja estan ordenats i ja
                                          // es pot acabar.

                    return;
                } else { // Hi ha més d'un element per ordenar!
                    int posProv=posInici+1; // Compararem el primer
                                            // element (el pivot)
                                            // amb els altres. Tots
                                            // els que siguin "més
                                            // petits" que el pivot
                                            // els posem fins a la
                                            // posició "posProv"
                                            // (que va canviant) i
                                            // tots els que siguin
                                            // "més grans" que el
                                            // pivot els posem
                                            // després de la posició
                                            // "posProv". Així,
                                            // doncs, la posició
                                            // "posProv" separa els
                                            // elements "més petits"
                                            // que el pivot, dels
                                            // "més grans"

                        for (int i=posInici+1;i<posFinal+1;i++) {
                                if (anteriorA(matriu[i],
                                    matriu[posInici])) {
                                    intercanvia(matriu,posProv,i);
                                    posProv++;
                                }
                        }
                    intercanvia(matriu,posInici,posProv-1);// Ara
                                                           // posem
                                                           // el
                                                           // pivot
                                                           // enmig
                                                           // dels
                                                           // dos
                                                           // grups.

                    quickSort(matriu,posInici,posProv-2);// Crida
                    quickSort(matriu,posProv,posFinal);  // recur-
                                                         // siva
                                                         // a la
                                                         // orde-
                                                         // nació
                                                         // a cadas-
                                                         // cun dels
                                                         // dos
                                                         // grups

                }
        }

        static void intercanvia (int[] matriu,  // Intercanvi entre
                                 int i,int j) { // dos elements de
                                                // la matriu "matriu"

            int temporal=matriu[i]; // Es necessita un espai
                                    // intermedi d'emmagatzenatge.

            matriu[i]=matriu[j];
            matriu[j]=temporal;
        }

        static boolean anteriorA (int obX,int obY) { // Criteri de
                                                     // comparació
                                                     // entre dos
                                                     // elements.

            return obX<obY;
        }

    }


    s'implementa el conegut algorisme d'ordenació QuickSort per tal d'ordenar una successió de nombres enters donats com a paràmetres per l'usuari. L'ús, des de la línia de comanaments, és aquest:
   
   
Pràctica
  • En l'exemple anterior, el punt clau és el mètode static boolean anteriorA (int obX,int obY), mitjançant el qual el programador decideix amb quin criteri compararà els objectes per tal d'ordenar-los. En aquest altre exemple (Projecte QSortC "Empty Project", fitxer QSortC.java) es tracta d'ordenar lexicogràficament una matriu de cadenes (strings) donada per l'usuari com a paràmetres. Les petites variacions respecte l'exemple anterior estan marcades en groc:

    class QSortC {

        public static void main (String[] args) {
            int quants=args.length;
            quickSort(args,0,quants-1); // Ara no cal convertir els
                                        // paràmetres perquè ja són
                                        // del tipus java.lang.String

            printMatriu(args);
        }
        static void printMatriu (String[] matriu) {// Ara el tipus
                                                 // ha de ser
                                                 // java.lang.String
            System.out.println("Resultat:");
            int n=matriu.length;
                for (int i=0;i<n;i++) {
                    System.out.print (matriu[i]+" ");
                }
            System.out.println("\n-----");
        }
        static void quickSort (String[] matriu, // Igualment, el
                               int posInici,    // tipus ha de ser
                               int posFinal) {  // java.lang.String
                if (posInici>=posFinal) {
                    return;
                } else {
                    int posProv=posInici+1;
                        for (int i=posInici+1;i<posFinal+1;i++) {
                                if (anteriorA(matriu[i],
                                    matriu[posInici])) {
                                    intercanvia(matriu,posProv,i);
                                    posProv++;
                                }
                        }
                    intercanvia(matriu,posInici,posProv-1);
                    quickSort(matriu,posInici,posProv-2);
                    quickSort(matriu,posProv,posFinal);
                }
        }
        static void intercanvia (String[] matriu,// Igualment, el
                                 int i,          // tipus ha de ser
                                 int j) {        // java.lang.String
            String temporal=matriu[i];
            matriu[i]=matriu[j];
            matriu[j]=temporal;
        }
        static boolean anteriorA (String obX,   // Igualment, el
                                  String obY) { // tipus ha de ser
                                                // java.lang.String
            return (obX.compareTo(obY))<0; // Mètode de la classe
                                           // java.lang.String per
                                           // ordenar lexicogràfica-
                                           // ment dues cadenes.
                                           // Vegeu-ne la documenta.
                                           // ció.

        }

    }


    L'ús, des de la línia de comanaments, és aquest:
   
 

 

 
Amunt