Esercizi su programmazione ricorsiva 1
Pericle Perazzo
[email protected]
http://info.iet.unipi.it/~fondii/
23 marzo 2012
Algoritmi e strutture dati
Ripasso di programmazione ricorsiva
Ripasso di programmazione ricorsiva
●
●
●
Algoritmo ricorsivo: algoritmo espresso in termini di se stesso.
Programmazione iterativa e programmazione ricorsiva sono equivalenti.
Vantaggi/svantaggi rispetto a programmazione iterativa:
●
●
●
meno efficiente
più semplice ed elegante per risolvere alcuni problemi
Condizioni necessarie per la correttezza:
●
●
presenza di uno o più casi base
convergenza verso i casi base
Algoritmi e strutture dati
Ripasso di programmazione ricorsiva
Relazioni di ricorrenza lineari
T  0 = a
k
T  n = bn T n−1 con n0
T  n ∈ O  n
k 1

Algoritmi e strutture dati
Esercizi
Esercizio 1
●
●
Scrivere una funzione ricorsiva che controlla se una stringa è palindroma
(ovvero se “rigirandola” non cambia, es. “ossesso” è palindroma).
Esempi di frasi palindrome:
●
●
●
I verbi brevi (“iverbibrevi”)
Aceto nell'enoteca (“acetonellenoteca”)
I topi non avevano nipoti (“itopinonavevanonipoti”)
Algoritmi e strutture dati
Esercizi
Esercizio 1 – Soluzione
●
Definizione ricorsiva di palindromicità:
●
●
●
Una stringa nulla è palindroma. Esempio: “”.
Una stringa di un carattere è palindroma. Esempio: “a”.
Una stringa tale che il primo e l'ultimo carattere sono uguali e la sottostringa
nel mezzo è palindroma, è palindroma. Esempio: “ossesso”.
Algoritmi e strutture dati
Esercizi
Esercizio 1 – Soluzione
1
2
3
4
5
6
7
8
bool palindroma(const string& s, int start, int len)
{
if (len <= 1) return true;
if (s[start]==s[start+len-1] && palindroma(s, start+1, len-2))
return true;
else
return false;
}
T 0=T 1 = a
T n = bT  n−2
T  n∈O n 
Algoritmi e strutture dati
Esercizi
Strumenti per l'esercitazione
BaseList<T>
IntList
Algoritmi e strutture dati
Esercizi
Classe IntList
●
IntList realizza un semplice lista di interi (“IntList.h”, “IntList.cpp”).
●
Ogni elemento è rappresentato da una struttura Elem, che contiene:
●
●
●
L'etichetta (int info),
Il puntatore all'elemento successivo (Elem* next)
All'interno della classe è definito il puntatore all'elemento di testa (Elem*
head).
Algoritmi e strutture dati
Esercizi
Classe IntList
●
Per fare debugging, sono definiti gli operatori put to (<<) e get from (>>).
●
È possibile usarli per immettere una lista da tastiera e stamparla a video.
IntList mia_lista;
cin >> mia_lista;
// acquisisce da tastiera
// nel formato: [1,3,12,0,2]
// (vengono ignorati gli spazi)
/* Elaborazioni varie... */
cout << mia_lista;
// stampa a video
// nel formato: [1,3,12,0,2]
Algoritmi e strutture dati
Esercizi
Classe IntList
●
Per programmare in modo ricorsivo su classi conviene operare nel seguente
modo:
1. Risolvere l'esercizio con una funzione private (es. _esercizio).
2. Per fare ricorsione, dichiararla static, e che prenda come argomento il
puntatore di testa (Elem* head).
3. Per fare debugging, definire una funzione public (es. esercizio) che non
fa altro che richiamare la funzione private con argomento il puntatore di
testa. Chiamare tale funzione dal main.
Algoritmi e strutture dati
Esercizi
Classe IntList
●
“IntList.h”:
1
2
3
4
5
6
7
●
class IntList{
private:
static void _esercizio(Elem* l);
public:
void esercizio(){_esercizio(head);}
};
“IntList.cpp”:
1
2
3
4
5
void IntList::_esercizio(Elem* l){
// ...
_esercizio(l->next);
// ...
}
Algoritmi e strutture dati
Esercizi
Esercizio 2
●
●
Aggiungere a IntList una funzione ricorsiva che somma ad ogni
elemento tutti i successivi.
Esempio – la lista:
3 → 4 → 6 → 4 → 5
deve diventare:
22 → 19 → 15 → 9 → 5
Algoritmi e strutture dati
Esercizi
Esercizio 2 – Soluzione
1
2
3
4
5
int IntList::_esercizio2(Elem* head){
if (head == NULL) return 0;
head->info += _esercizio2(head->next);
return head->info;
}
T  0 = a
T  n = bT n−1
T  n ∈ O  n 
Algoritmi e strutture dati
Esercizi
Esercizio 3
●
●
Aggiungere a IntList una funzione ricorsiva che rimuove dalla lista tutti i
“doppioni”.
Esempio – la lista:
3 → 4 → 6 → 4 → 3 → 3 → 6 → 7
deve diventare:
3 → 4 → 6 → 7
●
Suggerimento: sviluppare una funzione di appoggio
deleteAll(Elem*& l, int x)
che cancella tutti gli elementi di etichetta x dalla lista l.
Algoritmi e strutture dati
Esercizi
Esercizio 3 – Soluzione
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void IntList::deleteAll(Elem*& head, int x){
if (head == NULL) return;
if (head->info == x){
// cancello l'elemento di testa:
Elem* a = head;
head = head->next;
delete a;
deleteAll(head, x);
}
else // non lo cancello:
deleteAll(head->next , x);
}
void IntList::_esercizio3(Elem* head){
if (head == NULL) return;
deleteAll(head->next, head->info);
_esercizio3(head->next);
}
Algoritmi e strutture dati
Esercizi
Esercizio 3 – Soluzione
T  0 = a
T  n = bnT n−1
●
T  n ∈ O  n
2

Per ottenere una complessità minore bisogna ricorrere a tecniche di
ordinamento
Algoritmi e strutture dati
Esercizi
Esercizio 4
●
●
Aggiungere a IntList una funzione ricorsiva che conta le “vette”, cioè gli
elementi che sono maggiori di tutti i successivi.
Esempi:
6 → 4 → 5 → 3 → 1 → 10 → 1 → 10 → 3 → 3
vette = 2
6 → 4 → 8 → 6 → 10 → 1 → 7 → 2 → 1 → 4
vette = 3
●
Si suppone che tutte le etichette siano positive.
Algoritmi e strutture dati
Esercizi
Esercizio 4 – Soluzione
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int IntList::max(const Elem* head){
if (head == NULL) return 0;
int maxSucc = max(head->next);
if (head->info > maxSucc)
// l'elemento di testa e' il massimo:
return head->info;
else // l'elemento di testa NON e' il massimo:
return maxSucc;
}
int IntList::_esercizio4(const Elem* head){
if (head == NULL) return 0;
int maxSucc = max(head->next);
if (head->info > maxSucc)
// l'elemento di testa e' una vetta
return 1 + _esercizio4(head->next);
else // l'elemento di testa non e' una vetta
return _esercizio4(head->next);
}
Algoritmi e strutture dati
Esercizi
Esercizio 4 – Soluzione
T  0 = a
T  n = bnT n−1
T  n ∈ O  n
2

Algoritmi e strutture dati
Esercizi
Esercizio 4 – Soluzione alternativa
1 int IntList::_esercizio4b(const Elem* head, int& max){
2
if (head == NULL){ max = 0; return 0; }
3
int countPeaksSucc;
4
countPeaksSucc = _esercizio4b(head->next, max);
5
if (head->info > max){
6
// l'elemento di testa e' una vetta:
7
max = head->info;
8
return 1 + countPeaksSucc;
9
}
10
else return countPeaksSucc;
11 }
T  0 = a
T  n = bT n−1
T  n ∈ O  n 