Diferència entre revisions de la pàgina «M3 - Programació estructurada / Continguts UF1: Taules»

De wikiserver
Dreceres ràpides: navegació, cerca
(Emmagatzematge de l’entrada de dades en una taula)
(Emmagatzematge de l’entrada de dades en una taula)
Línia 119: Línia 119:
 
==Emmagatzematge de l’entrada de dades en una taula==
 
==Emmagatzematge de l’entrada de dades en una taula==
  
Com s’ha esmentat, els arrays són especialment útils per poder emmagatzemar de
+
:*Els arrays són útils per emmagatzemar un nombre arbitrari de dades provinents del sistema d’una entrada (per exemple, des del teclat).  
manera eficient un nombre arbitrari de dades provinents del sistema d’una entrada (per
+
:*Les dades s’aniran llegint una per una, i assignant a cadascuna de les posicions de l’array a partir del seu índex.  
exemple, des del teclat). Normalment, les dades s’aniran llegint una per una, i a mesura
+
 
que es faci, caldrà anar-les assignant a cadascuna de les posicions de l’array a partir del
+
: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).  
seu índex. Tot seguit veureu diferents esquemes per dur a terme aquesta tasca.
 
Si bé els exemples se centraran en l’ús del teclat, ja que és el sistema d’entrada que per
 
ara sabeu utilitzar, heu de tenir en compte que aquests esquemes seran aplicables a
 
qualsevol altre mecanisme d’entrada (per exemple, un fitxer). L’única condició és que
 
les dades estiguin en forma de seqüència, de manera que es puguin anar llegint una per
 
una, ordenadament.
 
  
 
===Entrada de seqüències de valors per teclat===
 
===Entrada de seqüències de valors per teclat===
  
Els arrays tenen sentit quan el programa ha de processar moltes dades, especialment
+
:'''Previ: ''': llegir seqüències de dades entrades des del teclat en una sola línia de text.
provinents de l’entrada del programa (com el teclat). Abans de continuar, val la pena
+
 
veure com es poden llegir seqüències de dades entrades des del teclat en una sola línia
+
:*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.
de text, de manera que sigui senzill emmagatzemar-les dins d’un array. Si bé ja sabeu
+
 
com llegir dades individualment des del teclat, fer-ho així pot ser una mica avorrit i
+
:*Quan no quedin valors, la propera instrucció de lectura, ara si, esperarà la introducció d'un nou valor.
molest amb vista a l’execució dels programes en què s’introdueixen moltes dades,
+
 
preguntant cada valor un per un i havent de pitjar la tecla de retorn cada vegada.
+
:*'''lector.nextLine()''';  provoca que esdescartin tots els valors pendents de llegir de la seqüència actual.
En realitat, quan s’usa una instrucció lector.next... i el programa s’atura esperant que
+
 
l’usuari introdueixi dades pel teclat, res no impedeix que, en lloc d’una única dada,
+
:*Es poden llegir seqüències de valors de diferents tipus de dades barrejats.
aquest n’escrigui més d’una abans de pitjar la tecla de retorn. O sigui, una seqüència de
+
 
valors. L’única condició és que cada valor individual estigui separat de la resta per
+
:*'''lector.hasNext...''' Serveix per comprovar el tipus de dades del valor a llegir abans de llegir-lo.
almenys un espai, de manera que siguin fàcilment identificables. Quan això succeeix,
 
tots els valors de la seqüència queden latents, pendents de lectura. Successives
 
invocacions a noves instruccions de lectura automàticament aniran consumint aquests
 
valors pendents, en lloc de causar una nova espera d’una entrada de l’usuari. Mentre
 
quedin valors a la seqüència pendents de llegir, les instruccions de lectura mai no
 
causaran una espera d’entrada de dades. Un cop la seqüència ha estat consumida
 
totalment, llavors sí que la propera instrucció de lectura causarà que el programa es
 
torni a aturar esperant una nova entrada de l’usuari. I així el cicle de lectura torna a
 
començar.
 
  
Dins d’aquest procés hi ha una crida amb un comportament especial: lector.nextLine();.
 
Quan aquesta crida s’invoca, automàticament es descarten tots els valors pendents de
 
llegir de la seqüència actual. La propera crida a una instrucció de lectura sempre causarà
 
que el programa s’aturi de nou i esperi una entrada de l’usuari.
 
Un fet important quan es llegeixen seqüències de diversos valors escrites des del teclat
 
és que res no impedeix que hi pugui haver valors de diferents tipus de dades barrejats.
 
Això tant pot ser per error de l’usuari en entrar les dades, com perquè el programa
 
realment espera una seqüència amb valors de diferents tipus intercalats. En qualsevol
 
cas, és important que abans de fer cap lectura d’una dada es comprovi si el tipus és el
 
que correspon usant les instruccions lector.hasNext....
 
 
Per llegir múltiples valors el més senzill és fer-ho mitjançant una estructura de repetició
 
Per llegir múltiples valors el més senzill és fer-ho mitjançant una estructura de repetició
 
que vagi invocant successivament les instruccions de lectura de dades. En usar aquest
 
que vagi invocant successivament les instruccions de lectura de dades. En usar aquest

Revisió del 13:22, 17 feb 2018

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 es 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 esdescartin 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 el més senzill és fer-ho mitjançant una estructura de repetició que vagi invocant successivament les instruccions de lectura de dades. En usar aquest mecanisme cal tenir present un fet ben important. S’ha de saber exactament quan heu obtingut ja totes les dades necessàries i cal deixar llegir. Normalment hi ha dues aproximacions depenent de si es coneix la quantitat de dades exactes que cal llegir o no.

Quantitat de dades coneguda

Si el nombre de valors que es vol llegir és conegut per endavant, per tractar la lectura de la seqüència de valors hi ha prou d’usar una estructura de repetició basada en un comptador. Aquest comptador controlarà el nombre de valors llegits i les iteracions finalitzaran en assolir el nombre de lectures que vulguem. Compileu i executeu l’exemple següent, en què es mostra com cal fer la lectura d’un seguit de valors enters. Si se n’escriuen més dels esperats, la resta es descarten. Fixeu-vos que no és necessari escriure tots els valors en una sola línia de text. Si la línia introduïda, abans de pitjar la tecla de retorn, no disposa de suficients valors, el programa s’atura esperant la resta. A més a més, aquest codi controla mitjançant una estructura de selecció si el valor que és a punt 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

Un cas més complex és quan el nombre de valors no és conegut a priori, ja que pot variar en diferents execucions del programa. Quan això succeeix, una solució simple seria preguntar simplement, abans de llegir cap valor, quantes dades s’introduiran, o bé fer que el primer valor dins de la seqüència n’indiqui la longitud. Si això no és possible, o es considera que no s’ha de fer, una altra opció és establir un valor especial que no forma part de les dades per tractar dins el programa, sinó que es considerarà com a marca de final de seqüència. Tan bon punt es llegeixi aquest valor, la lectura s’ha de donar per finalitzada. La condició per poder usar aquesta estratègia és que la marca no sigui un valor que pugui aparèixer mai entre els valors introduïts. Ha de ser únic. Per exemple, dins una llista de notes, qualsevol valor negatiu o major que 10 serviria. La resta de valors no es poden usar, ja que poden correspondre a una nota real que cal tractar. Si tots els valors possibles són acceptables dins de la seqüència una opció és 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. En aquest cas, l’estratègia per utilitzar és usar una estructura de repetició basada en semàfor. Aquest us indica si ja s’ha llegit la marca de fi i cal deixar d’iterar o no. El codi següent d’exemple llegeix una seqüència de valors enters de llargària arbitrària. Malauradament, hi ha circumstàncies sota les quals no és possible inicialitzar un array de manera que la seva mida s’ajusti exactament a la llargària de la seqüència de valors d’entrada. Hi ha dos motius que poden dur a aquesta situació. D’una banda, si simplement no es coneix a priori el nombre de dades que s’entraran, ja que en lloc del programa es pregunta prèviament, i per tant l’entrada de dades és d’una llargària desconeguda. En un cas com aquest, us haureu de conformar a triar un valor concret prefixat per a la mida de l’array i donar per fet que el nombre de dades d’entrada que el programa pot tractar és limitat. Si per algun motiu, en llegir les dades d’entrada, se supera aquest límit, com que no és possible emmagatzemar els valors excedents, els haureu d’ignorar. Per tant, caldrà triar aquesta mida arribant a un compromís entre un valor que sigui prou gran per no trobar-vos gaire sovint amb aquesta situació, però tampoc massa exagerat, per no malbaratar memòria. 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. Cal estudiar cada cas En un cas com aquest, en què es disposa d’un array amb una mida que mai no serà exactament igual al nombre de dades llegides des de l’entrada (de fet, normalment, serà inferior), només hi ha un rang de posicions en què hi ha dades llegides de l’entrada. La resta de posicions tenen valors per defecte que no tenen res a veure amb l’entrada, i per tant, no han de ser previstes a l’hora de fer cap tasca. Un altre aspecte important és que l’atribut length ara no és suficient per saber el rang de les dades vàlides. 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

Recorregut de taules

La sentència for millorada

Cerca seqüencial en taules

Cerca seqüencial en taules ordenades

Taules multidimensionals

Taules bidimensionals amb files de diferents longituds

Creació de taules bidimensionals

Recorregut en taules bidimensionals

Cerca en taules bidimensionals