|
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): |
|
|
 |
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: |
|
|
 |
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? |
|
|
 |
- 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:
|
 |
|
|
 |
- 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:
|
 |
|
|
|
|
 |
- 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:
|
 |
|
|
|
|
|
|
 |
|
|
|
|