M3 - Programació estructurada / Continguts UF1: Taules

De wikiserver
La revisió el 16:33, 2 nov 2020 per Rsort (Discussió | contribucions) (Entrada de seqüències de valors per teclat)
(dif) ← Versió més antiga | Versió actual (dif) | Versió més nova → (dif)
Dreceres ràpides: navegació, cerca

Taules (Arrays)

  • Conjunt de variables que conté valors tots del mateix tipus.
  • El nombre de posició de l'element s'anomena l'índex.
Taules
  • Conté N element.
  • Per referir-se als diferents elements de la taula s'utilitza el nom de la taula seguit per l'índex entre claudàtors ([]).
  • Primer element de la taula té índex 0.
  • Els elements són: c[0], c[1], c[2]...

Declaració i creació de taules

  • La següent declaració i expressió crea una taula, que conté 12 elements int, i emmagatzema la referència

de la taula en la variable c:

int c[] = new int[12];
  • Aquesta tasca també pot realitzar-se en dos passos, com es mostra a continuació:
int c[ ]; // declara la variable taula

c = new int[12]; // crea la taula; ho assigna a la variable tipus taula
  • En crear una taula, cadascun dels seus elements rep un valor predeterminat: zero per als elements numèrics, false per als elements boolean.
  • Quan es declara un taula, el seu tipus i els claudàtors poden combinar-se al principi de la declaració per indicar que tots els identificadors a la declaració són variables tipus taula. Per exemple, la declaració
double[] taula1, taula2;
indica que taula1 i taula2 són variables tipus “taula de double”. L'anterior declaració és
equivalent a:
double taula1[];
double taula2[];
o
double[] taula1;
double[] taula2;

Inicialització de taules

  • Es pot crear un taula i inicialitzar els seus elements amb una llista d'expressions separades per comes (llista inicialitzadora) tancada entre claus ({ i });
  • la longitud de la taula es determina sobre la base del nombre d'elements en la llista inicialitzadora. Per exemple,

la declaració:

int arrayEnters[] = { 10, 20, 30, 40, 50 };
crea un taula de cinc elements amb els valors d'índexs 0, 1, 2, 3 i 4. L'element arrayEnters [0] s'inicialitza amb 10, arrayEnters [1] s'inicialitza amb 20, i així en endavant.
Aquesta declaració no requereix que new creï l'objecte taula.
La grandària de la taula queda determinada pel nombre d'elements de la llista inicialitzadora.
Taules

Manipulació de dades

  • No és possible usar l’identificador de l’array directament per invocar operacions i així manipular les dades contingudes.
Per exemple, no és possible fer el següent:
int[] a = {10, 20, 30, 40, 50};
int[] b = {50, 60, 70, 80, 100};
int[] c = a + b;
  • Les dades emmagatzemades dins d’arrays nomès es poden manipular de manera individual, posició per posició.
  • Cada posició d’un array té exactament el mateix comportament que una variable de tipus primitiu.

Exemples

Inicialització de la taula mitjançant codi

L’aplicació següent crea una taula de 10 elements i assigna a cada element un dels enters parells del 2 al 20.

  • La propietat length ens dóna la longitud d’una taula
public class InicialitzacioTaula {
 
     public static void main(String args[]) {

       final int LONGITUD = 10; // declara la constant
       int taula[] = new int[LONGITUD]; // crea la taula
       // calcula el valor per a cada element de la taula
       int comptador = 0;
       while (comptador < taula.length) {
         taula[comptador] = 2 + 2 * comptador;
         comptador++;
       }
     }
   }

Sumar els elements d’una taula

public class SumaTaula {
  
     public static void main(String args[]) {

       int taula[] = {87, 68, 94, 100, 83, 78, 85, 91, 76, 87};
       int total = 0;
       // suma el valor de cada elemento al total
       int comptador = 0;
       while (comptador < taula.length) {
         total = total + taula[ comptador];
         comptador++;
       }
       System.out.println("Total dels elements de la taula: "+ total);
     }
   }

Emmagatzematge de l’entrada de dades en una taula

  • Els arrays són útils per emmagatzemar un nombre arbitrari de dades provinents del sistema d’una entrada (per exemple, des del teclat).
  • Les dades s’aniran llegint una per una, i assignant a cadascuna de les posicions de l’array a partir del seu índex.
Els esquemes dels exemples següent utilitzen el teclat com a sistema d’entrada de dades. Són aplicables a altres mecanismes d'entrada (per exemple, un fitxer).

Entrada de seqüències de valors per teclat

Previ: : llegir seqüències de dades entrades des del teclat en una sola línia de text.
  • Quan s’usa una instrucció lector.next... es pot introduir una seqüència de valors separats de la resta per almenys un espai. Es llegeix un valor i la resta queden pendents de noves instruccions de lectura, que llegiran automàticament el següent valor.
  • Quan no quedin valors, la propera instrucció de lectura, ara si, esperarà la introducció d'un nou valor.
  • lector.nextLine(); provoca que es descartin tots els valors pendents de llegir de la seqüència actual.
  • Es poden llegir seqüències de valors de diferents tipus de dades barrejats.
  • lector.hasNext... Serveix per comprovar el tipus de dades del valor a llegir abans de llegir-lo.
  • Per llegir múltiples valors s'utilitza una estructura de repetició que variarà en funció de si es coneix la quantitat de dades exactes que cal llegir o no.

Quantitat de dades coneguda

  • S'utilitza un comptador. per controlar el nombre de lectures. Si se n’escriuen més dels esperats, la resta es descarten.
L’exemple següent, mostra com cal fer la lectura d’un seguit de valors enters.
  • No és necessari escriure tots els valors en una sola línia de text.
  • Controla mitjançant una estructura de selecció si el valor que és apunt de ser llegit serà realment un enter o no.
import java.util.Scanner;

   public class LectorValorsConeguts {
   //Es llegiran 5 valors.

     public static void main(String[] args) {

       final int NUM_VALORS = 5;
       int dades[] = new int[NUM_VALORS];
       Scanner lector = new Scanner(System.in);
       System.out.println("Escriu " + NUM_VALORS + " enters.");
       //Es llegeixen exactament NUM_VALORS valors.
       int numValorsLlegits = 0;
       while (numValorsLlegits < NUM_VALORS) {
       //Abans de llegir, comprovem si realment hi ha un enter.
         if (lector.hasNextInt()) {
           int valor = lector.nextInt();
           dades[numValorsLlegits] = valor;
           numValorsLlegits++;
           System.out.println("Valor " + numValorsLlegits + " llegit: " + valor);
         } else {
         //Si el valor no és enter, es llegeix però s’ignora.
         //No s’avança tampoc el comptador.
             lector.next();
           }
       }
       //Els valors que sobrin a la darrera línia escrita es descarten.
       lector.nextLine();
       System.out.println("Ja s’han llegit " + NUM_VALORS + " valors.");
    }
  }

Quantitat de dades desconeguda

  • Quan el nombre de valors no és conegut a priori, es pot:
  • Abans de llegir cap valor, demanar quants dades s’introduiran.
  • Fer que el primer valor dins de la seqüència n’indiqui la longitud.
  • Establir un valor especial que no forma part de les dades per tractar dins el programa, com a marca de final de seqüència. Per exemple, dins una llista de notes, qualsevol valor negatiu o major que 10 serviria
  • Usar un valor d’un tipus de dada diferent. Per exemple, un programa que processa valors reals arbitraris per fer càlculs matemàtics podria usar un caràcter com a marca de fi.
  • Quan no és possible ajustar exactament la mida del array a la llargària de la seqüència de valors, cal triar un valor concret prefixat intentant que en cap cas es superi. En el cas que hi hagués valors excedents, es perdrien. Per exemple, si ja sabeu que el nombre d’estudiants en una classe pot oscil·lar, però mai no es permetrà que n’hi hagi més de 80, es pot triar aquest valor com a mida de l’array.
  • Quan la mida del array no s'ajusta a la seqüència de valors, cal anar en compte per tractar només les dades llegides des de l'entrada. L’atribut length només indica la capacitat de la taula. Per tant, serà necessari disposar d’una variable auxiliar addicional, de tipus enter, en què s’emmagatzemi el nombre de dades que realment hi ha dins de la taula.
import java.util.Scanner;

     public class LectorValorsDesconeguts {

       public static void main(String[] args) {

         final int MARCA_FI = -1;
         final int MAX_VALORS = 80;
         int dades[] = new int[MAX_VALORS];
         int elements = 0;
         Scanner lector = new Scanner(System.in);
         System.out.println("Escriu diferents valors enters. Com a màxim: " + MAX_VALORS);
         System.out.println("Després del darrer valor escriu un " + MARCA_FI);
         //Es llegeixen com a molt MAX_VALORS valors.
         boolean marcaTrobada = false;
         while (!marcaTrobada && elements < dades.length) {
         //Abans de llegir, comprovem si realment hi ha un enter.
           if (lector.hasNextInt()) {
             int valor = lector.nextInt();
             //És la marca de fi?
             if (valor == MARCA_FI) {
             //Sí que ho és.
               marcaTrobada = true;
             } else {
               //No. És un valor que ha de ser tractat.
                 dades[elements] = valor;
                 elements++;
               }
           } else {
             //Si el valor no és enter, es llegeix però s’ignora.
               lector.next();
             }
         } //Els valors que sobrin a la darrera línia escrita es descarten.
         lector.nextLine();
         System.out.println("Ja s’han llegit tots els valors."); 
     }
   }

Tractament seqüencial de taules

La sentència for

  • Quan es coneix, a priori, la quantitat exacta de dades que cal llegir, es recomanable utilitzar la sentència for.

Sintaxi i estructura

   for (inicialització comptador ; expressió booleana ; increment comptador) {
     Instruccions per la lectura i introducció de dades a la taula.
   }

Exemple:

   for (i = 0; i<10; i++)
    { ........ }

Recorregut de taules

  • Quan treballem amb taules, molt sovint haurem de fer càlculs en què estan implicats tots els valors emmagatzemats. En aquest cas, cal fer-ne un recorregut seqüencial de les posicions i anar-les processant per obtenir un resultat final.
  • Exemple: calcular la mitjana aritmètica d’un seguit de notes, que requereix sumar els valors de totes i cadascuna i dividir el resultat entre el seu nombre.
public class MitjanaNotesRecorregut {
   //Programa que fa un recorregut d’un array: càlcul de la mitjana aritmètica.

     public static void main(String[] args) {
     //Es parteix d’un array que conté tots els valors.

       double[] arrayNotes = {4.2, 5.5, 9.1, 10, 4.9, 8, 8.5, 7, 6.6, 5, 9};
       //Acumulador de la suma de valors.
       double acumulat = 0;
       double resultat;
       //Cal recórrer tot l’array d’extrem a extrem.
       for (int i = 0; i < arrayNotes.length; i++) {
         acumulat = acumulat + arrayNotes[i];
       }
       resultat = acumulat / arrayNotes.length;
       System.out.printf("La mitjana és: %.2f \n", resultat);
     }
   }

La sentència for millorada

  • Itera a través dels elements d'una taula sense utilitzar un comptador (amb la qual cosa, evita la possibilitat de “sortir-se” de la taula).
  • Simplifica el codi per iterar a través d'un array.
  • Només pot utilitzar-se per obtenir elements de la taula; no pot utilitzar-se per modificar els elements.
La sintaxi d’una instrucció for millorada és:
   for (paràmetre: nomTaula) {
     instruccions
   }
on:
  • paràmetre té dues parts: un tipus i un identificador (per exemple, int numero)
  • nomTaula és la taula a través de la qual s'iterarà.
  • El tipus del paràmetre ha de concordar amb el tipus dels elements en la taula.
  • Exemple: calcular la suma dels enters en una taula de qualificacions d’estudiants.
public class ForMillorat {

     public static void main( String args[] ){

       int taula[] = { 87, 68, 94, 100, 83, 78, 85, 91, 76, 87 };
       int total = 0;
       // suma el valor de cada element al total
       for (int numero : taula)
         total = total+numero;

       System.out.printf( "Total d'elements de la taula: %d\n", total );
     }
   }

Cerca seqüencial en taules

  • La cerca seqüencial compara cada element del vector amb el valor desitjat, fins que el troba o acaba de llegir el vector sencer.
  • NO s’ha d’utilitzar la instrucció for.
  • Exemple: donat un array de notes, ens interessa saber si algú ha tret un 10.
public class CercaSequencial {

     public static void main(String args[]) {
     //Es parteix d’un array de notes amb els seus valors.
     
       double[] arrayNotes = {4.2, 5.5, 9.1, 10, 4.9, 8, 8.5, 7, 6.6, 5, 9};
       //Semàfor. S’ha trobat?
       boolean trobat = false;
       //Comptador de posicions.
       int i = 0;
       //Es va mirant cada posició, mentre no s’arriba al final i no es trobi un 10
       while ((i < arrayNotes.length) && (!trobat)) {
         if (arrayNotes[i] == 10) {
           trobat = true;
         }
         i = i + 1;
       }
       //S’ha trobat?
       if (trobat) {
         System.out.println("Algú ha tret un 10.");
       } else {
          System.out.println("Ningú no ha tret un 10");
         }
     }
   }

Cerca seqüencial en taules ordenades

  • Donat que el vector està ordenat, si trobem un valor més gran que el que busquem, ja estem segurs de que no trobarem l’element desitjat i podem finalitzar la cerca.
  • Exemple: Cercar si hi ha una nota de 7:
public class CercaSequencialOrdenada {

     public static void main(String args[]) {
     //Es parteix d’un array de notes amb els seus valors.

       double[] arrayNotes = {4.2, 4.9, 5, 5.5, 6.6, 7, 8, 8.5, 9, 9.1, 10};
       //Semàfor. S’ha trobat?
       boolean trobat = false;
       //Semafor. Hem d'acabar?
       boolean acabar=false;
       //Comptador de posicions.
       int i = 0;
       //Es va mirant cada posició, mentre no s’arriba al final i no es trobi un 10
       while ((i < arrayNotes.length) && (!trobat)&&(!acabar)) {
         if (arrayNotes[i] == 7) {
         //Ja l'hem trobat
         trobat = true;
         } else if (arrayNotes[i]>7){
           //Ja no la trobarem
           acabar=true;
           }
         else i = i + 1;
       }
       //S’ha trobat?
       if (trobat) {
         System.out.println("Algú ha tret un 7.");
       } else {
           System.out.println("Ningú no ha tret un 7");
         } 
     }
   }

Taules multidimensionals

  • De dues dimensions (matrius o taules bidimensionals) s'utilitzen per representar taules de valors. Presenten la informació ordenada en files i columnes.
  • S'utilitzen dos subíndexs per identificar un element. Per convenció, el primer identifica la fila de l'element i el segon la seva columna.
  • Poden tenir més de dues dimensions.
  • Poden tenir diferent nombre d'elements per cada fila.
  • En general, a un taula amb m files i n columnes se li diu taula de m per n.
Taules
  • Es poden inicialitzar mitjançant inicialitzadors de taules a les declaracions.
  • Per exemple: unan taula bidimensional b amb dues files i dues columnes podria declarar-se i inicialitzar-se amb inicialitzadors de taules niats, com es mostra a continuació:
int b[ ] [ ] = { { 1, 2 }, {3, 4} };
  • Els valors de l’inicialitzador s'agrupen per fila entre claus: 1 i 2 inicialitzen a b[ 0 ][ 0 ] i b[ 0 ][ 1 ], respectivament; 3 i 4 inicialitzen a b[ 1 ][ 0 ] i b[ 1 ][ 1 ], respectivament.
  • Les files poden tenir diferents longituds.
  • Les taules multidimensionals es mantenen com a taules de taules unidimensionals. Per tant, la taula b a la declaració anterior està realment composta de dos taules unidimensionals separades: la primera llista conté els valors { 1, 2 } i la segona els valors { 3, 4 }.

Taules bidimensionals amb files de diferents longituds

  • Les longituds de les files en la taula b no han de ser iguals. Per exemple:
int b[ ][ ] = { { 1, 2 }, { 3, 4, 5 } };
  • La taula b consta de dos elements que representen les files de la taula bidimensional.
  • Cada element de b és una referència a una taula unidimensional de variables int.
  • La taula de la fila 0 és una taula unidimensional amb dos elements (1 i 2), i la taula de la fila 1 és un taula unidimensional amb tres elements (3, 4 i 5).

Creació de taules bidimensionals

  • Declaració de la taula b amb una assignació d'una referència a una taula de tres per quatre:
int b[ ][ ] = new int[ 3 ][ 4 ];
  • Es poden utilitzar variables per especificar les dimensions de la taula, ja que new crea taules en temps d'execució, no en temps de compilació.
  • Un taula multidimensional, en la qual cada fi la té un nombre diferent de columnes, pot crear-se de la següent manera:
int b[][] = new int[ 2 ][ ]; // crea 2 files
b[ 0 ] = new int[ 5 ]; // crea 5 columnes per a la fila 0
b[ 1 ] = new int[ 3 ]; // crea 3 columnes per a la fila 1
  • La fila 0 té cinc columnes i la fila 1 té 3.

Recorregut en taules bidimensionals

  • Tots els esquemes fonamentals per treballar amb arrays bidimensionals es basen en dues estructures de repetició imbricades, una per tractar cada fila i l’altra per tractar cada valor individual dins de la fila.
  • L’atribut length inidica el nombre de files que hi ha.
  • El nombre de valors d'una fila és variable[indexFila].length
  • Exemple: Disposem d’una matriu amb les notes dels alumnes i les volem imprimir
public class MatriuNotes {

     public static void main(String[] args) {
     
       int i, j;
       double notes[][] = {
         {9.44, 2.52, 9.69, 5.32, 8.88, 3.00, 3.88, 6.99},
         {5.11, 2.18, 2.13, 1.32, 3.50, 9.93, 2.65, 2.85},
         {1.74, 6.67, 5.25, 0.05, 8.32, 1.84, 3.04, 5.76},
         {9.24, 8.37, 3.80, 4.51, 4.48, 2.88, 4.82, 8.78},
         {2.82, 8.62, 8.82, 1.22, 5.22, 8.55, 6.76, 2.25},
         {9.69, 7.59, 9.65, 5.71, 9.23, 5.70, 9.84, 7.77},
         {7.32, 3.74, 4.60, 7.58, 5.55, 0.09, 8.18, 6.54},
         {7.62, 0.21, 3.88, 1.03, 8.38, 2.71, 9.80, 8.57},
         {6.95, 8.24, 3.10, 3.41, 1.27, 9.94, 3.99, 0.51},
         {0.10, 9.88, 4.24, 1.49, 7.51, 0.28, 3.61, 5.07},
         {3.92, 8.54, 1.68, 1.61, 8.16, 6.59, 6.25, 7.67},
         {4.10, 4.55, 3.11, 9.75, 5.91, 1.42, 1.63, 8.65},
         {2.83, 2.54, 4.37, 2.45, 0.95, 4.71, 7.41, 6.75},
         {9.33, 2.11, 2.89, 0.76, 1.86, 3.63, 2.64, 5.43},
         {5.94, 1.02, 1.97, 9.37, 5.38, 3.19, 1.09, 0.18},
         {4.49, 0.39, 0.23, 5.15, 1.66, 1.66, 3.91, 6.96}};
         for (i = 0; i < notes.length; i++) {
           for (j = 0; j < notes[i].length; j++) {
             System.out.printf("%6.2f ", notes[i][j]);
           }
         System.out.println("");
       }
     }
   }

Cerca en taules bidimensionals

  • La cerca implica haver de gestionar dos índexs per anar avançant per files i columnes.
  • En assolir l’objectiu cal sortir de les dues estructures de repetició imbricades.
  • Cal tenir un semàfor que s’avaluï en tots dos bucles. Per exemple, suposeu que el programa de gestió de notes vol cercar si algun estudiant ha tret un 0 en algun dels exercicis al llarg del curs. Caldrà anar mirant fila per fila totes les notes de cada estudiant, i quan es trobi un 0, acabar immediatament la cerca.
Quan fem una cerca en taules, mai s’ha d’utilitzar la instrucció for
  • cal anar amb molt de compte a inicialitzar i incrementar correctament l’índex per recórrer la posició de cada fila.
public class BuscaNota {

     public static void main(String[] args) {

       int i, j;
       boolean trobat=false;
       double notes[][] = {
         {7.32, 3.74, 4.60, 7.58, 5.55, 0.09, 8.18, 6.54},
         {7.62, 0.21, 3.88, 1.03, 8.38, 2.71, 9.80, 8.57},
         {6.95, 8.24, 3.10, 3.41, 1.27, 9.94, 3.99, 0.51},
         {0.10, 9.88, 4.24, 1.49, 7.51, 0.28, 3.61, 5.07},
         {3.92, 8.54, 1.68, 1.61, 8.16, 6.59, 6.25, 7.67},
         {4.10, 4.55, 3.11, 9.75, 5.91, 1.42, 1.63, 8.65},
         {2.83, 2.54, 4.37, 2.45, 0.95, 4.71, 7.41, 6.75},
         {9.33, 2.11, 2.89, 0.00, 1.86, 3.63, 2.64, 5.43},
         {5.94, 1.02, 1.97, 9.37, 5.38, 3.19, 1.09, 0.18},
         {4.49, 0.39, 0.23, 5.15, 1.66, 1.66, 3.91, 6.96}};
       i=0;
       while (i<notes.length&&!trobat){
         j=0;
         while(j<notes[i].length&&!trobat){
           if( notes[i][j]==0){
             trobat=true;
           }
           j++;
         }
       i++;
       }
       if (trobat){
         System.out.println("Hi ha algun alumne amb un 0");
       }
       else{
         System.out.println("No hi ha cap alumne amb un 0");
       }
     }
   }