Mòdul 3

Pràctica 2: Matrius, vectors i d'altres cucs (II)   
Tornar presentació tema
Pràctica 1 Pràctica 2 Pràctica 3 Pràctica 4 Pràctica 5 Pràctica 6  
     
 

A la pràctica anterior, omplir una matriu ha estat fet d'una manera ben matussera... element per element! Ara mirarem d'automatitzar les coses. Al cap i a la fi, d'això tracta la informàtica...

 
     
  Omplir una matriu:  
     
Al projecte Matrius de la pràctica anterior, crea la classe MatriusDeNombres amb aquest codi:  
     
 

/**
* Manipulació elemental de matrius II.
*
* @author Carles Romero
* @version 2004/02/08
*/

public class MatriusDeNombres {

    /**
     * Una matriu que conté nombres enters.
     */

    int[] elsNombres;

    /**
     * Mètode constructor per a objectes de la classe
     * MatriusDeNombres.
     * @param n la longitud de la matriu elsNombres
     */

    public MatriusDeNombres (int n) {
// constructor
        elsNombres=new int[n];
    }

}

 
     
  La compiles crees un objecte d'aquesta classe, amb 5 com a paràmetre del mètode constructor i, després, l'inspecciones:  
     
 
 
     
  Apareix l'única variable d'instància que hi has definit, això és, la matriu elsNombres, la qual també pots inspeccionar:  
     
 
 
     
  Efectivament, tal com mana la línia  
     
 
        elsNombres=new int[n];
 
     
  del mètode constructor public MatriusDeNombres (int n), la matriu elsNombres té 5 elements, nombres enters, que, per defecte (no has manat altra cosa!) són 0.  
     
  Ara l'omplim,ara...  
     
  Ara afegeix aquest mètode, que servirà per omplir-la amb nombres enters positius. Retoca també, el mètode constructor per tal que, tot just al construir l'objecte, la matriu ja estigui plena:  
     
 

/**
* Manipulació elemental de matrius II.
*
* @author Carles Romero
* @version 2004/02/08
*/
public class MatriusDeNombres {

    /**
     * Una matriu que conté nombres enters.
     */
    int[] elsNombres;

    /**
     * Mètode constructor per a objectes de la classe
     * MatriusDeNombres.
     * @param n la longitud de la matriu elsNombres
     */
    public MatriusDeNombres (int n) { // constructor
        elsNombres=new int[n];

        posaValorsInicials();

    }
 
    /**
     * Mètode que posa un 1 al primer lloc de la matriu elsNombres
     * (índex 0), un 2 al segon lloc (índex 1), etc.
     */

    public void posaValorsInicials () {
        int quants=elsNombres.length;
            for (int i=0;i<quants;i++) {
                elsNombres[i]=i+1;
            }
    }
 
}
 
     
  Aquesta és una manera estàndar de manipular matrius: el codi comença per preguntar com és de llarga la matriu:  
     
 
        int quants=elsNombres.length;
 
     
  tot dipositant a la variable quants el valor de la variable length (longitud) de la matriu elsNombres (totes les matrius la tenen la variable length!). Després, amb una estructura de control for(...){...}, (un moment! ara mateix t'ho expliquem!) omple, un per un, els elements de la matriu:  
     
 
            for (int i=0;i<quants;i++) {
                elsNombres[i]=i+1;
            }
 
     
  amb el nombre i+1 en aquest cas, però igual podries haver-hi posat  
     
 
                elsNombres[i]=i*i-3*i;
 
     
  o qualsevol altra cosa...  
     
  A la pràctica anterior has vist una estructura de bucle. Ara en tenim una altra: l'estructura de control for(...){...} és un altre tipus de bucle ("loop") que es fa servir molt i molt. Requereix un comptador enter (int i, en el nostre cas) al qual se li ha de donar un valor inicial (i=0), una condició que pot ser verdadera o falsa (i<quants), i una operació d'increment del comptador (i=i++, que és una abreviatura de i=i+1). El codi entre els delimitadors "{" i "}" s'executa una i una altra vegada fins que la condició resulti falsa. El nostre codi  
     
 
            for (int i=0;i<quants;i++) {
                elsNombres[i]=i+1;
            }
 
     
  és completament equivalent a aquest altre, amb una estructura while(...){...}:
 
     
 
        int i=0;
            while (i<quants) {
                elsNombres[i]=i+1;
                i++; 
// equivalent a i=i+1
            }
 
     
  Adona't que el que es fa, tant si s'escriu d'una manera com d'una altra, és repetir l'acció del cos del bucle per als valors de la variable i següents: 0, 1, 2, 3, ..., quants-1.

Si ara inspecciones la matriu elsNombres,
 
     
 
 
     
  veuràs que, efectivament és plena amb els valors que establia el codi del mètode public void posaValorsInicials ().


Pot ser interessant que analitzis què passa si canvies l'expressió i+1 d'aquest mètode per una altra expressió en funció de i.
 
     
  Canvis i més canvis...  
     
  La mateixa tècnica que t'ha servit per omplir una matriu, ara pots aplicar-la per canviar-ne allò que hi ha enmagatzemat. Per exemple, amb aquest nou mètode  
     
 
    < ... codi anterior ... >
            for (int i=0;i<quants;i++) {
                elsNombres[i]=i+1;
            }
    }

 
    /**
     * Mètode que substitueix els nombres enmagatzemats a la matriu
     * elsNombres pel residu que en resulta en dividir-los per n.
     * @param n el nombre (el mòdul!) pel qual es divideixen els
     * elements de la matriu elsNombres
     */

    public void aModulN (int n) {
        int quants=elsNombres.length;
            for (int i=0;i<quants;i++) {
                elsNombres[i]=elsNombres[i]%n;
            }
    }
 
}
 
     
  podràs veure l'efecte de l'operador binari "%" sobre els elements de la matriu: cada nombre enmagatzemat serà substituït pel residu que en resulta en dividir-lo per l'enter n, que és el paràmetre que cal passar en executar el mètode:  
     
  En l'exemple següent s'havia creat prèviament una nova còpia de la matriu elsNombres amb longitud 16.  
     
 
 
     
  Ara canviar-ne l'ordre:    
     
  El següent mètode:  
     
 
    < ... codi anterior ... >
            for (int i=0;i<quants;i++) {
                elsNombres[i]=elsNombres[i]%n;
            }
    }
 
    /**
     * Mètode per intercanviar les posicions de dos elements de
     * la matriu elsNombres.
     * @param m la posició d'un dels elements a intercanviar
     * @param n la posició de l'altre dels elements a intercanviar
     */

    public void intercanvia (int m,int n) {
        int buffer=elsNombres[m];

         // necessitem un dipòsit intermedi!

        elsNombres[m]=elsNombres[n];
        elsNombres[n]=buffer;
    }
 
}
 
     
  agafa l'element que hi ha a la posició (quan diguem "posició" en realitat heu de llegir "índex") m,  
     
 
        int buffer=elsNombres[m];
 
     
  i el guarda al dipòsit provisional int buffer ("buffer", en anglès, vol dir "esmorteïdor" i, en l'argot informàtic, té el sentit de "dipòsit provisional de dades"). Després, agafa l'element que hi ha a la posició (índex) n i el copia a la posició (índex) m. El valor que hi havia a la posició m es perd i, per això, cal guardar-lo abans en un dipòsit provisional.  
     
 
        elsNombres[m]=elsNombres[n];
 
     
  Finalment, copia el valor guardat a buffer (el valor que hi havia inicialment a la posició m!) a la posició n:  
     
 
        elsNombres[n]=buffer;
 
     
  i, així, l'intercanvi de posicions queda complet.  
     
  Prova-ho: amb una matriu elsNombres de vuit elements:  
     
 
 
     
  aplica el mètode public void intercanvia (int m,int n) amb els paràmetres 2 i 5:  
     
 
 
     
  i ara inspecciona la matriu:  
     
 
 
     
  Efectivament!, el 3 i el 6, que eren a les posicions 2 i 4, han intercanviat els seus llocs!  
     
  I ara... un parell d'exercicis:  
     
Es tracta que, a partir dels valors inicials:  
     
 
 
     
  escriguis dos nous mètodes. Un, que s'ha de dir public void capgira (), ha d'aconseguir això:  
     
 
 
     
  és a dir, capgirar completament la matriu: el primer element ha d'anar a l'últim lloc, el segon al penúltim, etc.  
     
  L'altre mètode, public void permutacióCircularDescendent (), ha de fer desplaçar cada element un lloc: el segon element al primer lloc, el tercer al segon, etc. excepte el primer, que ha d'anar a parar a l'últim lloc:  
     
 
 
     
  Aquests mètodes han d'incloure el mètode public void intercanvia (int m,int n) en el seu codi. Si no te'n surts (ei! només si no te'n surts, eh?) aquí tens una solució possible dels dos exercicis (n'hi ha més!).  
     
  I per què no?  
     
I per què no escrius ara un altre mètode, public void permutacioCircularAscendent (), que faci desplaçar cada element un lloc però a la inversa d'abans: el primer element al segon lloc, el segon al tercer, etc. excepte l'últim, que ha d'anar a parar al primer lloc?  
     
    Tornar al principi