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 n0 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 = bT 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 = bT 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 = bnT 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 = bnT 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 = bT n−1 T n ∈ O n