Capitolo 11
Ricorsione
Lucidi relativi al volume:
Java – Guida alla programmazione
James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Definizioni ricorsive
Una definizione che definisce qualcosa in base a sé stessa è
chiamata definizione ricorsiva.
I discendenti di una persona sono i figli della persona e
tutti i discendenti dei figli della persona.
Un elenco di numeri è un numero o un numero seguita da
una virgola e un elenco di numeri.
Un algoritmo ricorsivo è un algoritmo che invoca sé stesso
per risolvere istanze più piccole o più semplici di un
problema.
Il fattoriale di un numero n è n volte il fattoriale di n-1.
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Fattoriale
Una definizione imprecisa
1
n!
n (n 1)
n0
1 n 1
Una definizione precisa
n0
1
n!
n (n -1)! n 1
I puntini di sospensione
comunicano al lettore di
utilizzare l'intuizione per
riconoscere lo schema
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Metodi ricorsivi
Un metodo ricorsivo possiede generalmente due parti.
Una parte di terminazione che ferma la ricorsione.
È chiamata caso di base.
Il caso di base deve avere una soluzione semplice o
banale.
Una o più chiamate ricorsive.
È chiamato caso ricorsivo.
Il caso ricorsivo chiama lo stesso metodo ma con
argomenti più semplici o più piccoli.
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Method factorial()
public static int factorial(n) {
if (n == 0) {
Caso di base
return 1;
}
else{
return n * factorial(n-1);
}
}
Il caso ricorsivo gestisce una versione
più semplice (piccola) dell'attività
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Method factorial()
public static int factorial(n) {
if (n == 0) {
return 1;
}
else{
return n * factorial(n-1);
}
}
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
int n = Integer.parseInt(stdin.readLine());
int nfactorial = factorial(n);
System.out.println(n + “! = “ + nfactorial;
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
factorial()
int
n = 3
nfactorial
return
n
*
=
factorial(n);
factorial(n-1);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
factorial()
n = 1
return
n
*
factorial(n-1);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
factorial()
n = 1
return
n
*
factorial(n-1);
factorial()
n = 0
return
1;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
factorial()
n = 1
return
n
*
factorial(n-1);
factorial()
n = 0
return
1;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
factorial()
n = 1
factorial()
n = 0
return n * 1;
return
1;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return
n
*
factorial(n-1);
factorial()
n = 2
return
n
*
factorial(n-1);
factorial()
n = 1
return 1 * 1;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
factorial()
n = 2
return n * 1
factorial()
n = 1
return 1 * 1;
return
n
*
factorial(n-1);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
factorial()
n = 3
factorial()
n = 2
nfactorial
return
n
*
=
factorial(n);
factorial(n-1);
return 2 * 1
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int
nfactorial
=
factorial(n);
factorial()
n = 3
return n * 2;
factorial()
n = 2
return 2 * 1;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
factorial()
int
n = 3
nfactorial
=
factorial(n);
return 3 * 2;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
factorial()
int nfactorial = 6;
n = 3
return 3 * 2;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Invocazione ricorsiva
Un nuovo record di attivazione viene creato per ogni
invocazione del metodo
Comprese le invocazioni ricorsive
main()
int nfactorial = 6;
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Numeri di Fibonacci
Sviluppati da Leonardo Pisano nel 1202.
Analisi della velocità con cui i conigli possono figliare in
circostanze ideali.
Supposizioni
Una coppia di conigli maschio e femmina figlia sempre
e produce un'altra coppia di conigli maschio e
femmina.
Un coniglio diventa sessualmente maturo dopo un
mese; anche il periodo di gestazione è pari a un mese.
Pisano voleva conoscere la risposta alla domanda: quanti
conigli esisteranno dopo un anno?
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Numeri di Fibonacci
La sequenza generata è: 1, 1, 2, 3, 5, 8, 13, 21, 34, …
Il numero di coppie per un mese è uguale alla somma del
numero di coppie nei due mesi precedenti.
Inserimento dell'equazione di Fibonacci
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Numeri di Fibonacci
Pattern del metodo ricorsivo
if ( codice di terminazione soddisfatto ) {
return value;
}
else{
esegui chiamata ricorsiva più semplice;
}
public static int fibonacci(int n) {
if (n <= 2) {
return 1;
}
else{
return fibonacci(n-1) + fibonacci(n-2);
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Numeri di Fibonacci
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Ricorsione infinita
Un errore di programmazione comune
nell'utilizzo della ricorsione è non terminare
le chiamate ricorsive.
Il programma continuerà la ricorsione fino a esaurimento
della memoria.
Occorre assicurarsi che le chiamate ricorsive siano
eseguite su sottoproblemi più semplici o piccoli, e che
l'algoritmo abbia un caso di base che termini la ricorsione.
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Ricerca binaria
Confrontare la voce con l'elemento centrale dell'elenco. Se la voce
corrisponde all'elemento centrale, la voce desiderata è stata
individuata e la ricerca termina.
Se la voce non corrisponde, allora se la voce è nell'elenco deve
trovarsi a sinistra o a destra dell'elemento centrale.
L'elenco secondario corretto può essere ricercato utilizzando la
stessa strategia.
0
1
2
3
4
5
6
10
24
33
45
56
81
95
entryquesto
to this element.
If the
matches, the la ricerca è
ConfrontareCompare
la voce con
elemento.
Seentry
corrispondono,
If thesignifica
entry is less
45,
then the in elenco,
finita. Se lasearch
voce is
è successful.
minore di 45,
che,than
se è
presente
entry, if ait sinistra
is in the list,
must be to the
left in elements
0-2.
può solo trovarsi
dell'elemento
centrale,
ossia compresa
tra 0
If the
entry èis più
greater
thandi
45,45,
then
thesolo
entry,
if it is inathe
e 2. Se
invece
grande
può
trovarsi
destra
list, mustcentrale,
be to the ossia
right incompresa
elements 4-6.
dell'elemento
tra 4 e 6.
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Sviluppo della ricerca per una rubrica
public class AddressEntry {
private String personName;
private String telephoneNumber;
public AddressEntry(String name, String number) {
personName = name;
telephoneNumber = number;
}
public String getName() {
return personName;
}
public String getNumber() {
return telephoneNumber;
}
public void setName(String Name) {
personName = Name;
}
public void setTelephoneNumber(String number) {
telephoneNumber = number;
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Ricerca binaria
Interfaccia pubblica
Dovrebbe essere il più semplice possibile
Nessun parametro estraneo
public static AddressEntry recSearch(AddressEntry[]
addressBook, String name)
Interfaccia privata
Invocata dall'implementazione dell'interfaccia pubblica
Dovrebbe supportare l'invocazione ricorsiva per
implementazione dell'interfaccia privata
private static AddressEntry recSearch(AddressEntry[]
addressBook, String name, int first, int last)
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Ricerca binaria
Implementazione dell'interfaccia pubblica
public static AddressEntry recSearch(AddressEntry[]
addressBook, String name) {
return recSearch(addressBook, name, 0,
addressBook.length-1);
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Implementazione dell'interfaccia privata
static AddressEntry recSearch(AddressEntry[] addressBook,
String name, int first, int last) {
// caso di base: se la sezione dell'array è vuota
l'elemento non è stato trovato
if (first > last)
return null;
else{
int mid = (first + last) / 2;
// se il valore è stato trovato la ricerca termina
if (name.equalsIgnoreCase(addressBook[mid].getName()))
return addressBook[mid];
else if (name.compareToIgnoreCase(
addressBook[mid].getName()) < 0) {
// se il valore è presente è nella metà sinistra
return recSearch(addressBook, name, first, mid-1);
}
else // array[mid] < value
// se il valore è presente è nella metà destra
return recSearch(addressBook, name, mid+1, last);
}
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Verifica
Sviluppare casi di verifica per provare
ogni possibile situazione univoca
public static void main(String[] args){
// l'elenco deve essere ordinato
AddressEntry addressBook[] = {
new AddressEntry("Audrey", "434-555-1215"),
new AddressEntry("Emily" , "434-555-1216"),
new AddressEntry("Jack" , "434-555-1217"),
new AddressEntry("Jim"
, "434-555-2566"),
new AddressEntry("John" , "434-555-2222"),
new AddressEntry("Lisa" , "434-555-3415"),
new AddressEntry("Tom"
, "630-555-2121"),
new AddressEntry("Zach" , "434-555-1218")
};
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Verifica
Ricerca del primo elemento
AddressEntry p;
// primo elemento
p = recSearch(addressBook, "Audrey");
if (p != null) {
System.out.println("Audrey's telephone number is " +
p.getNumber());
}
else{
System.out.println("No entry for Audrey");
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Verifica
Ricerca dell'elemento centrale
p = recSearch(addressBook, "Jim");
if (p != null) {
System.out.println("Jim's telephone number is " +
p.getNumber());
}
else{
System.out.println("No entry for Jim");
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Verifica
Ricerca dell'ultimo elemento
p = recSearch(addressBook, "Zach");
if (p != null) {
System.out.println("Zach's telephone number is " +
p.getNumber());
}
else{
System.out.println("No entry for Zach");
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Verifica
Ricerca di un elemento inesistente
p = recSearch(addressBook, "Frank");
if (p != null) {
System.out.println("Frank's telephone number is " +
p.getNumber());
}
else{
System.out.println("No entry for Frank");
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Efficienza della ricerca binaria
L'altezza di una struttura binaria è il
numero massimo di confronti necessari per
la ricerca in un elenco
Una struttura con 31 nodi ha altezza 5
In generale, una struttura con n nodi ha
un altezza pari a log2(n+1)
La ricerca in un elenco con un miliardo di
nodi richiede solo 31 confronti
La ricerca binaria è efficiente!
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
Mergesort è un ordinamento ricorsivo che divide
concettualmente il suo elenco di n elementi da ordinare in
due elenchi secondari di dimensione n/2.
Se un elenco secondario contiene più di un elemento,
l'elenco secondario viene ordinato con una chiamata
ricorsiva a mergeSort().
Dopo che i due elenchi secondari di dimensione n/2 sono
ordinati, vengono uniti per produrre un singolo elenco
ordinato di dimensione n.
Questo tipo di strategia è detta dividi e conquista: il problema
è diviso in sottoproblemi di complessità minore e le soluzioni
dei sottoproblemi sono utilizzate per produrre la soluzione
generale.
Il tempo di esecuzione del metodo mergeSort() è
proporzionale a n log n.
Questa prestazione è a volte detta prestazione linearitmica.
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
Si supponga di voler ordinare
l'array mostrato.
'Q' 'W' 'E' 'R' 'T' 'Y' 'U' 'I' 'O' 'P'
Dopo l'ordinamento dei due elenchi secondari, l'array sarà:
'E' 'Q' 'R' 'T' 'W' 'I' 'O' 'P' 'U' 'Y'
Left sorted sublist
Right sorted sublist
Ora è possibile svolgere l'attività di unione dei due array per
ottenere:
'E' 'I' 'O' 'P' 'Q' 'R' 'T' 'U' 'W' 'Y'
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
Interfaccia pubblica
Dovrebbe essere il più semplice possibile
Nessun parametro estraneo
public static void mergeSort(char[] a)
Interfaccia privata
Invocata dall'implementazione dell'interfaccia
pubblica
Dovrebbe supportare l'invocazione ricorsiva per
implementazione dell'interfaccia privata
private static void mergeSort(char[] a, int left, int
right)
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
private static void
mergeSort(char[] a, int left, int right) {
if (left < right) {
// esistono più elementi da ordinare.
// per prima cosa, ordina in modo ricorsivo gli
elenchi secondari
int mid = (left + right)/2;
mergeSort(a, left, mid);
mergeSort(a, mid+1, right);
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
// poi unisce gli elenchi secondari ordinati
// nell'array temp
char[] temp = new char[right - left + 1];
int j = left;// indice dell'elemento più piccolo a sinistra
int k = mid + 1;// indice dell'elemento più piccolo a destra
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
for (int i = 0; i < temp.length; ++i) {
// memorizza l'elemento più piccolo in temp
if ((j <= mid) && (k <= right)) {
// deve prendere il più piccolo tra a[j]
// e a[k]
if (a[j] <= a[k]) // sinistra contiene l'elemento più
piccolo
temp[i] = a[j];
++j;
}
else // destra contiene l'elemento più piccolo
temp[i] = a[k];
++k;
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
else if (j <= mid) // può prendere solo da sinistra
temp[i] = a[j];
++j;
}
else // può prendere solo da destra
temp[i] = a[k];
++k;
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
// infine copia temp in a
for (int i = 0; i < temp.length; ++i) {
a[left + i] = temp[i];
}
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Mergesort
L'invocazione considera gli elementi di
EQRTWYUIOP con indici compresi
nell'intervallo da 5 a 9 e produce
EQRTWIOPUY
L'invocazione iniziale considera
gli elementi di QWERTYUIOP
nell'intervallo da 0 a 9 e
produce EIOPQRTUWY
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Ricorsione e iterazione
L'iterazione può essere più efficiente
Sostituisce le chiamate ai metodi con i cicli
Viene utilizzata meno memoria (nessun record di
attivazione per ogni chiamata)
Molti problemi sono risolti più naturalmente con la ricorsione
Torri di Hanoi
Mergesort
La scelta dipende dal problema e dal contesto della soluzione
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Confusione giornaliera
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Confusione giornaliera
Attività
Genera tutte le possibili permutazioni delle lettere
Per n lettere ci sono n! possibilità
n scelte per la prima lettera
n-1 scelte per la seconda lettera
n-2 scelte per la terza lettera
…
Iteratore
Oggetto che produce valori successivi in una sequenza
Progettazione
Classe iteratore PermuteString che supporta
l'enumerazione delle permutazioni
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Classe PermuteString
Costruttore
public PermuteString(String s)
Costruisce un generatore di permutazioni per la stringa
s
Metodi
public String nextPermutation()
Restituisce la successiva permutazione della stringa
associata
public boolean morePermutations()
Indica se esiste una permutazione non enumerata della
stringa associata
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Classe PermuteString
Variabili istanza
private String word
Rappresenta la parola da permutare
private int index
Posizione all'interno della parola su cui operare
public PermuteString substringGenerator
Generatore di sottostringhe
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Costruttore
public PermuteString(String s){
word = s;
index = 0;
if (s.length() > 1) {
String substring = s.substring(1);
substringGenerator = new PermuteString(substring);
}
else{
substringGenerator = null;
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Considerare
Cosa accade?
PermuteString p = new PermuteString(“ath“);
p
word: "ath"
index: 0
substringGenerator:
word: "th"
index: 0
substringGenerator:
word: "h"
index: 0
substringGenerator:
null
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Metodo
public boolean morePermuations() {
return index < word.length;
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Metodo
public boolean nextPermutation() {
if (word.length() == 1) {
++index;
return word;
}
else{
String r = word.charAt(index)
+ substringGenerator.nextPermutation();
if (!substringGenerator.morePermutations()) {
++index;
if (index < word.length()) {
String tail = word.substring(0, index)
+ word.substring(index + 1);
substringGenerator = new permuteString(tail);
}
}
return r;
}
}
Java – Guida alla programmazione - James Cohoon, Jack Davidson
Copyright © 2004 - The McGraw-Hill Companies srl
Confusione giornaliera