Obiettivo: Scrivere ancora altri metodi ricorsivi.
Attività:
i
in poi (ricorsivo e iterativo).
Nota: Questo metodo vi sarebbe stato utile per l'esercizio 4.1:
non l'avevate definito? Male... [soluzione]i
a j
nulli
(ricorsivo e iterativo). [soluzione]Scriveremo il programma Esercizio11_4
. Iniziamo quindi a scrivere
nel file Esercizio11_4.java il seguente codice:
triangolareInferiore
il metodo
che controlla se una matrice è triangolare inferiore.m[i][j]
quando i < j
sono uguali a 0
(Figura 1).
1 0 0 0 2 3 0 0 3 1 5 0 2 5 3 1Figura 1. Una matrice triangolare inferiore
1 0 0 0 1 0 0 0 2 3 0 0 2 3 0 0 3 1 5 0 3 1 5 0 2 5 3 1 2 5 3 1Figura 2. Una matrice è triangolare inferiore se la prima riga ha tutti zeri dopo la diagonale e se la sottomatrice è triangolare inferiore.
triangolareInferiore
dovrà restituire un
boolean
e avrà un parametro m
di tipo
int[][]
.private
con i due parametri, mentre lasceremo quello public
con un solo parametro. Il suo codice sarà:
private
, che fa tutto il lavoro, sarà:
private
)
che controlli se gli elementi di una riga di una matrice sono tutti zero
da un certo indice in poi. Visto che una riga di una matrice è
un array, il metodo avrà intestazione
a
ha sicuramente
tutti gli elementi dopo l'indice i
uguali a zero quando
l'indice è più grande della lunghezza dell'array;a
ha tutti
gli elementi dopo l'indice i
uguali a zero se a[i]
è uguale a zero e se (questa è la chiamata ricorsiva)
ha tutti gli elementi dopo l'indice i+1
uguali a zero.tuttiZeri
sarà:
tuttiZeri
ritorna true
se i≥a.length
oppure se a[i]==0
e tuttiZeri(a,i+1)
.
Questo può essere espresso dalla seguente espressione:
tuttiZeri
può essere riscritto
in modo più elegante ed efficiente in questo
modo:
||
e &&
che valutano i due argomenti solo quando
necessario. Per esempio, quando i ≥ a.length
tutto il resto dell'espressione (((a[i] == 0) && tuttiZeri(a,i+1))
)
non verrà valutata. Se avessimo usato gli operatori logici |
e &
avremmo ottenuto un errore durante l'esecuzione perché
non si può valutare a[i]
quando i
è
maggiore di a.length-1
.tuttiZeri
possiamo completare triangolareInferiore
:
tuttiZeri
, possiamo riscrivere
il codice in modo più elegante ed efficiente, considerando che
una matrice è triangolare inferiore dalla riga r
in
poi se r>=m.length
oppure se gli elementi
della riga m[r]
sono tuttiZeri
da r+1
in poi e se la matrice è triangolareInferiore
da r+1
in poi. L'espressione equivalente a quanto detto sopra
è:
triangolareInferiore
può essere riscritto
triangolareInferioreIterativa(int[][] m)
è molto simile. Basta fare un ciclo in cui si controlla che tutti
gli elementi di una riga r
sono zeri da r+1
in poi:
Esercizio11_4
sarà:
triangolare
sarà molto semplice:
diagonale
sarà quindi:
tuttiZeri
per scrivere efficientemente triangolareInferiore
.
Ora basterà dichiararlo public
invece di private
.a
ha gli elementi da i
a j
uguali a zero se:
i
è maggiore di j
;a[i]
è uguale
a zero e, ricorsivamente, ha tutti gli elementi da i+1
a j
uguali a zero.tuttiZeri(int[] a, int i, int j)
sarà
quindi:
tuttiZeri
,
potremmo riscrivere il codice dell'esercizio4.4 in questo modo:
i
a j
:
i
a j
. Questo non è molto efficiente:
al primo elemento diverso da zero sappiamo che dovremo ritornare false
anche senza controllare tutti i rimanenti. Per sfruttare questa osservazione
possiamo riscrivere il metodo così:
if (a[k] != 0) break;
fa terminare il ciclo appena
si trova un elemento diverso da zero. Alla fine del ciclo se k >
j
vuol dire che il ciclo è stato completato oppure che i
era maggiore di j
e quindi il ciclo non è stato nemmeno
iniziato. In entrambi i casi il metodo deve restituire true
,
altrimenti, se k
è minore o uguale a j
, vuol
dire che si è incappati nel break
, allora c'è almeno
un elemento diverso da zero (per l'appunto a[k]
) ed il metodo
deve tornare false
. Tutto quanto detto si traduce in
triangolareInferioreIterativa
valgono le
stesse considerazioni, quindi il codice può essere riscritto nel modo
seguente:
1 0 0 0 1 2 3 2 2 3 0 0 0 3 0 0 3 1 5 0 0 1 5 0 2 5 3 1 0 5 3 1Figura 3. La matrice trasposta si ottiene scambiando gli elementi della prima riga con quelli della prima colonna e poi trasponendo la sottomatrice ottenuta togliendo la prima riga e la prima colonna.
triangolareInferiore
,
simuleremo la chiamata sulla sottomatrice chiamando, ricorsivamente sulla
stessa matrice, ma sulla riga successiva.trasposta
consisterà dunque nella sola chiamata
al metodo private
con parametro aggiuntivo la riga 0
da cui si deve partire per trasporre la matrice:
private
sarà invece:
for
più esterno. Notate anche che questa
volta, a differenza delle altre, non si può spezzare prima il ciclo
con un break
perché per trasporre una matrice occorre
scambiare tutti gli elementi fino all'ultimo. Aij
si indende il minore complementare
di aij
, cioè la matrice ottenuta da A
togliendo la riga i
e la colonna j
.determinante
sarà:
private int[][] minore
che restituisce il minore complementare
sarà: