Lezione in Aula del 29 Novembre 2001

Verso la conclusione del corso


COSA E' STATO FATTO A LEZIONE

Questo documento contiene un RIASSUNTO degli argomenti presentati a lezione. Per eventuali chiarimenti rivolgersi ai docenti.

Una classe per i numeri razionali ("soluzione" di un esercizio assegnato al termine della Lezione in Aula del 6 Novembre 2001)

Il file sorgente TestRational.java definisce una classe (che usa la classe Rational e la classe AConsoleReader) che legge due numeri razional da terminale, legge quale tra le 4 operazioni deve essere effettuata, e scrive su terminale il risultato dell'operazione sui numeri letti.

Il file sorgente Rational.java contiene uno "scheletro" della classe Rational, in cui i metodi numerator() e denominator() restituiscono la stringa "1". Tale file puo' essere usato per compilare ed eseguire TestRational.java PRIMA di aver completato la scrittura della classe Rational.

Il file sorgente MathUtil.java contiene metodi per il calcolo del MCD di due int e di due BigInteger.

Il file sorgente Rational.java contiene una implementazione della classe Rational che utilizza degli int per rappresentare numeratore e denominatore.

Il file sorgente Rational.java contiene una implementazione della classe Rational che utilizza dei BigInteger per rappresentare numeratore e denominatore.

Un esercizio sugli array ("soluzione" di un esercizio assegnato al termine della Lezione in Aula del 23 Novembre 2001)

Una prima soluzione ("buona")

Questa soluzione usa il metodo:

   /*
      AI: a != null
      AF: restituisce il numero di volte che "e occorre in a"
   */
   public static int howMany(int[] a, int e)
che abbiamo sviluppato la scorsa lezione.

   /*
      AI: a != null
      AF: restituisce un nuovo array, ottenuto da a eliminando
          tutte le occorrenze di e
   */
public static int[] deleteAll(int a[], e)
{  
   if (a==null) throw new IllegalArgumentException();

   int n = howMany(a,e);
   int[] b = new int[a.length-n];
   
   int j=0;

   /*
      IC: 0 <= i <= a.length 
          AND b[0..j-1] contiene gli elementi di a[0..i-1] diversi da e
   */
   for(i=0; i < a.length; i++)
   {  if (a[i]!=e)
      {  b[j]=a[i];
         j++;
      }
   }

   /*
      b contiene gli elementi di a diversi da e
   */
   return b; 
}

Una seconda soluzione ("brutta")

Questa soluzione usa (oltre al metodo howMany) il metodo:

   /*
      AI: a != null
      AF: restituisce un nuovo array ottenuto da a eliminando
          la prima occorrenza di e
   */
   public static int[] deleteFirst(int[] a, int e)
che abbiamo sviluppato la scorsa lezione.

   /*
      AI: a != null
      AF: restituisce un nuovo array, ottenuto da a eliminando
          tutte le occorrenze di e
   */
public static int[] deleteAll(int a[], e)
{  
   if (a==null) throw new IllegalArgumentException();

   int n = howMany(a,e);
   int[] b = a;
   
   /*
      IC: 0 <= j <= n
          AND b e' ottenuto da a eliminando le prime j occorrenze di e
   */
   for(j=0; j < n; j++)
      b = deleteFirst(b,e);

   /*
      b contiene gli elementi di a diversi da e
   */
   return b; 
}
Questa soluzione e' "brutta" perche' ogni chiamata di deleteFirst puo' richiedere di visitare un numero consistente di elementi di a (ad es. la meta'), e puo' essere necessario eseguire la deleteFirst per un numero consistente di volte (ad es. la meta' degli elementi di a). Si consideri ad esempio un array di 20000 elementi, costituito da 10000 "zeri" seguiti da 10000 "uni":
c = {0,...,0,1...,1}}
La chiamata
deleteAll(c,1)
richiede (con la seconda soluzione) di eseguire la deleteFirst 10000 volte, e ciscuna chiamata richiede di visitare 10000 elementi dell'array. In totale vengono visitati: 10000*10000=100000000 elementi.

Con la prima soluzione, invece, ciascun elemento di a e' visitato una volta, quindi vengono visitati 20000 elementi.

Inoltre la prima soluzione richiede di fare una sola new, per allocare un array che ha alpiu' tanti elementi come a (nell'esempio di prima un array di 10000 elementi). Mentre la seconda soluzione richiede di fare tante new (quante sono le occorrenze di e in a) per allocare array che hanno alpiu' tanti elementi come a (nell'esempio di prima 10000 array di 19999, 19998,...,10000 elementi).

Nuovi esercizi sugli array

   /*
      AI: 
      AF: L' array a e' stato modificato rimpiazzando
          tutte le occorrenze di oldE con newE
          (se a==null non e' stato fatto niente)
   */
void replaceAll(int a[], oldE, newE)
{  
   if (a==null) return;

   /*
      IC: 0 <= j <= a.length
          AND in a[0..i-1] tutte le occorrenze di oldE 
              sono state rimpiazzate da newE 
   */
   for (i=0; i < a.length; i++)
      if (a[i] == oldE) a[i] = newE;

   /*
     In a tutte le occorrenze di oldE sono state rimpiazzare da newE
   */
}

   /*
      AI: a!=nulll AND n>=0
      AF: L' array a e' stato modificato rimpiazzando
          le prime n occorrenze di oldE con newE
          (se ci sono meno di n occorrenze le rimpiazza tutte)
   */
void replaceFirst(int a[], oldE, newE, n)
{
   if ((a==null) || (n<0)) throw new IllegalArgumentException();
   
   int counter = 0;
   int i = 0;

   /*
      IC: 0 <= i <= a.length
          AND 0<= counter <= n
          AND in a[0..i-1] tutte le occorrenze di oldE (che erano counter)
              sono state rimpiazzate da newE 
   */
   while ((i < a.length) && (counter < n))
   {  if (a[i]==oldE) a[i] = newE;
      i++;
   }
}  

ESERCIZI DA SVOLGERE (assegnati al termine della Lezione in Aula)

Per eventuali chiarimenti rivolgersi ai docenti.

  1. Scrivere un metodo reverse che, dato un array a, rovescia i suoi elementi. Ad esempio: trasforma {1,2,3,4} in {4,3,2,1}.