Laboratorio di Algoritmi e Strutture Dati II Esercitazione Guidata Teresa M.A. Basile – [email protected] – Dipartimento di Informatica Università degli Studi di Bari “Aldo Moro” 1 _TRACCIA_ Cosa consegnare Consegnare in un archivio compresso la risoluzione della traccia in C++ (sorgenti di tutte le ADT utilizzate ed eseguibile) e una descrizione sintetica, in un file di testo, della strategia utilizzata che risponda ai seguenti punti: ● ● ● ● ● Input: elencare i dati di input. Per ognuno fornire il nome, il tipo, primitivo o derivato, ed una brevedescrizione; Output: elencare i dati di output. Per ognuno fornire il nome, il contenuto, il tipo – primitivo o derivato – ed una breve descrizione; Ipotesi ed assunzioni: riportare l’elenco di ipotesi ed assunzioni. Ad es., per i dati di input specificare eventuali ordinamenti ipotizzati sui dati, esistenza di duplicati, i limiti sui valori, il limite sul volume, la fine dei dati, il supporto di memorizzazione, le modalità (a menu, su richiesta, da altri programmi etc.); per i dati di output, l’ordine e il limite sul volume, il supporto di memorizzazione, l’eventuale periodicità etc.; Strutture dati: elencare le strutture dati scelte per la risoluzione del problema, motivandone brevemente la scelta; Strategia solutiva: Riportare in linguaggio naturale la descrizione della strategia solutiva del programma principale e di tutte le eventuali procedure. 2 _TRACCIA_ (1) Fornire in un file util bin tree.cpp la realizzazione in C++ delle seguenti funzioni che operano su alberi binari di elementi di tipo intero: ● ● ● int odd(bintree<int> &T, int k) calcola e restituisce il numero di nodi di livello k il cui valore e' dispari; int even_leafs(bintree<int> &T) calcola e restituisce il numero di foglie il cui valore e' pari; int leafs_with_even_parent(bintree<int> &T) calcola e restituisce il numero di foglie che hanno come genitore un nodo il cui valore e' pari. Prevedere un main che acquisisca automaticamente un albero binario e mostri a video il test delle funzioni implementate. 3 int odd(BinTree<T,R> &T, int k) Descrizione : calcola e restituisce il numero di nodi di livello k il cui valore e dispari; Input : - BinTree<T,R> &T: generica struttura albero; - int k: numero intero identificante il livello da analizzare Output : - intero: intero rappresentante il numero di nodi con valore dispari ad un determinato livello Ipotesi e assunzioni: - le strutture devono necessariamente valori interi; non sono richiesti ulteriori vincoli - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva: - Scansione per livelli dell'albero; - attraverso un calcolo sui nodi è possibile conoscere il livello scandito; - raggiunto il livello richiesto si effettua il controllo dei valori contenuti 4 nei nodi e, in caso di valore dispari, si incrementa un contatore apposito int even_leafs(BinTree<T,R> &T) Descrizione : calcola e restituisce il numero di foglie il cui valore e pari; Input : BinTree<T,R> &T: generica struttura albero; Output : intero: intero rappresentante il numero di foglie con valore pari Ipotesi e assunzioni: - le strutture devono necessariamente valori interi; non sono richiesti ulteriori vincoli - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva: - Scansione per livelli dell'albero; - quando si incrocia un nodo senza figli, si effettua un controllo sul valore contenuto; - se pari, si incrementa un apposito contatore 5 proposta void binVisita(Nodo n, BinAlbero &T){ if (!T.binAlberoVuoto()){ // 1 esame anticipato del nodo n if (!T.sinistroVuoto(n)) binVisita(T.figlioSinistro(n), T) // 2 esame simmetrico del nodo n if (!T.destroVuoto(n)) binVisita(T.figlioDestro(n), T) // 3 esame differito del nodo n } } esame del nodo: se foglia(nodo) (sinistroVuoto(nodo) && destroVuoto(nodo)) allora se (leggiNodo(nodo,T)%2==0) foglie_pari++ 6 int leafs_with_even_parent(BinTree<T,R> &T) Descrizione : calcola e restituisce il numero di foglie che hanno come genitore un nodo il cui valore è pari Input : - BinTree<T,R> &T: generica struttura albero; Output : - intero: intero rappresentante il numero di foglie con valore pari Ipotesi e assunzioni: - le strutture devono necessariamente valori interi; non sono richiesti ulteriori vincoli - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva: - Scansione per livelli dell'albero; - quando si incrocia un nodo senza figli si effettua un controllo sul valore contenuto nel padre; - se pari, si incrementa un apposito contatore 7 proposta void binVisita(Nodo n, BinAlbero &T){ if (!T.binAlberoVuoto()){ // 1 esame anticipato del nodo n if (!T.sinistroVuoto(n)) binVisita(T.figlioSinistro(n), T) // 2 esame simmetrico del nodo n if (!T.destroVuoto(n)) binVisita(T.figlioDestro(n), T) // 3 esame differito del nodo n } } esame del nodo: se foglia(nodo) (se sinistroVuoto(nodo) && destroVuoto(nodo)) allora se (leggiNodo(binpadre(nodo))%2==0) foglie_con_padre_pari++ 8 _TRACCIA_ (2) Dopo aver acquisito un albero n-ario di elementi di tipo double (o int) fornire la realizzazione in C++ delle seguenti funzioni: 1) double somma(AlberoN<T> Tree) restituisce la somma di tutti gli elementi dell'albero n-ario T calcolata in modo RICORSIVO; 2) double sommaLivello(AlberoN<T> Tree, int k) restituisce la somma di tutti gli elementi di livello k dell'albero nario calcolata in modo RICORSIVO; 3) pari(AlberoN<T> Tree) restituisce tutti i nodi dell'albero T radici di sottoalberi aventi nodi la cui somma e' pari; 4) dispari(AlberoN<T> Tree) restituisce tutti i nodi dell'albero T che sono radici di sottoalberi aventi nodi (inclusa la radice) la cui somma e' dispari; 5) double media_livello(AlberoN<T> Tree, int k) restituisce la media dei valori di tutti i nodi dell'albero T di livello k; 9 _TRACCIA_ (2) Prevedere nel main una funzione di popolamento automatico dell'albero n-ario T evitando di acquisirlo di volta in volta da tastiera e visualizzarne il contenuto prima di eseguire in ordine le seguenti operazioni: 1) 2) 3) 4) 5) visualizza visualizza visualizza visualizza visualizza il il il il il valore valore valore valore valore restituito restituito restituito restituito restituito da da da da da somma(T) sommaLivello(T,k) pari(T) dispari(T) media_livello(T,k) 10 double somma(AlberoN<T> Tree) Descrizione : calcola e restituisce la somma di tutti gli elementi dell'albero n-ario Tree Input : - AlberoN<T> Tree: generica struttura albero; Output : - reale: rappresentante la somma di tutti gli elementi dell'albero nario Tree Ipotesi e assunzioni: - le strutture possono contenere valori di tipo interi o reali, non sono richiesti ulteriori vincoli; - il calcolo deve avvenire in modo ricorsivo; - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva:.... - Scansione per livelli dell'albero; // Visita albero - Per ogni nodo dell'albero viene richiamata ricorsivamente una funzione di somma che lavora su un sottoalbero la cui radice è rappresentata dal nodo che stiamo analizzando; - questo fino ad arrivare ad un nodo foglia. 11 double somma(AlberoN<T> Tree) double somma(AlberoN<_double_> T){ AlberoN<_double_>::nodo n = T.Radice(); return(somma(T,n)); } double somma(AlberoN<_double_> T, AlberoN<_double_>::nodo n){ _double_ s = T.leggiNodo(n); if (!T.Foglia(n)){ AlberoN<_double_>::nodo k = T.primoFiglio(n); while(!T.ultimoFratello(k)){ s += somma(T,k); k = T.succFratello(k); } s += somma(T,k); } return(s); } 12 double sommaLivello(AlberoN<T> Tree, int k) Descrizione : calcola e restituisce la somma di tutti gli elementi di livello k dell'albero n-ario Tree; Input : - AlberoN<T> Tree: generica struttura albero; - int k: numero intero identificante il livello da analizzare Output : - reale: rappresentante la somma di tutti gli elementi dell'albero n-ario Tree ad un determinato livello Ipotesi e assunzioni: - le strutture possono contenere valori di tipo interi o reali, non sono richiesti ulteriori vincoli; - il calcolo deve avvenire in modo ricorsivo; - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva: - Scansione per livelli dell'albero; - attraverso un calcolo sui nodi è possibile conoscere il livello scandito; - raggiunto il livello richiesto si effettua il calcolo della somma dei valori contenuti nei nodi 13 double sommaLivello(AlberoN<T> Tree, int k) double sommaLivello(AlberoN<_double_> T, int k){ AlberoN<_double_>::nodo n = T.radice(); return(sommaLivello(T,n,1,k)); } double sommaLivello(AlberoN<_double_> T, AlberoN<_double_>::nodo n, int currLev, int h){ _double_ s = 0; if (!T.foglia(n)){ if (currLev == h) return T.legginodo(n); else { AlberoN<_double_>::nodo n1 = T.primoFiglio(n); while(!T.ultimoFratello(n1)){ s+= sommaLivello(T,n1,currLev++,k); n1 = T.succFratello(n1); } s += sommaLivello(T,n1,currLev++,k); } } else if (currLev == h) s = T.legginodo(n); return(s); } 14 double media_livello(AlberoN<T> Tree, int k) Descrizione : calcola e restituisce la media di tutti gli elementi di livello k dell'albero n-ario Tree; Input : - AlberoN<T> Tree: generica struttura albero; - int k: numero intero identificante il livello da analizzare Output : - reale: rappresentante la media di tutti gli elementi dell'albero n-ario Tree ad un determinato livello Ipotesi e assunzioni: - le strutture possono contenere valori di tipo interi o reali, non sono richiesti ulteriori vincoli; - il valore restituito sarà maggiore o uguale a 0; Strategia risolutiva: - Scansione per livelli dell'albero; - attraverso un calcolo sui nodi è possibile conoscere il livello scandito; - raggiunto il livello richiesto si effettua il calcolo della somma dei valori contenuti nei nodi e si incrementa un apposito contatore che identifica il numero di nodi per il determinato livello da analizzare 15 double media_livello(AlberoN<T> Tree, int k) Considerazioni: come sommalivello ma incrementando un contatore per il numero di nodi sommati 16 pari(AlberoN<T> Tree) Descrizione : restituisce tutti i nodi dell'albero Tree che sono radici di sottoalberi aventi nodi la cui somma e' pari Input : - AlberoN<T> Tree: generica struttura albero; Output : - struttura che memorizza i nodi con la particolare caratteristica richiesta, ovvero che siano radici di sottoalberi aventi nodi la cui somma è pari Ipotesi e assunzioni: - le strutture albero possono contenere valori di tipo interi o reali, non sono richiesti ulteriori vincoli; - la struttura di appoggio per memorizzare i nodi di output è una lista ..... (peculiarità della lista che hanno indotto a questa scelta) Strategia risolutiva:.... - Scansione per livelli dell'albero; // Visita albero bfs - Per ogni nodo dell'albero (uso di somma(Albero,Nodo)) viene richiamata ricorsivamente una funzione di somma che lavora su un sottoalbero la cui radice è rappresentata dal nodo che stiamo analizzando, questo fino ad arrivare ad un nodo foglia; - Se il valore così calcolato è pari, si memorizza il nodo in esame nella opportuna struttura dati scelta per contenere il risultato 17 dispari(AlberoN<T> Tree) Descrizione : restituisce tutti i nodi dell'albero Tree che sono radici di sottoalberi aventi nodi (inclusa la radice) la cui somma e' pari Input : - AlberoN<T> Tree: generica struttura albero; Output : - struttura che memorizza i nodi con la particolare caratteristica richiesta, ovvero che siano radici di sottoalberi aventi nodi (incluso il nodo radice stesso) la cui somma è dispari Ipotesi e assunzioni: - le strutture albero possono contenere valori di tipo interi o reali, non sono richiesti ulteriori vincoli; - la struttura di appoggio per memorizzare i nodi di output è una lista ..... (peculiarità della lista che hanno indotto a questa scelta) Strategia risolutiva:.... - Scansione per livelli dell'albero; // Visita albero bfs - Per ogni nodo dell'albero (uso di somma(Albero,Nodo)) viene richiamata ricorsivamente una funzione di somma che lavora su un sottoalbero la cui radice è rappresentata dal nodo che stiamo analizzando, questo fino ad arrivare ad un nodo foglia; - Se il valore così calcolato sommato al valore contenuto nel nodo in esame, è dispari, si memorizza il nodo in esame nella opportuna struttura dati scelta per contenere il risultato 18