Strutture Dinamiche Fondamenti di Informatica 1
Indice Allocazione e de-allocazione di memoria Liste e loro gestione Companies, srl 2
Allocazione e cancellazione di memoria malloc (sizeof (TipoDato)); Crea in memoria una variabile di tipo TipoDato, e restituisce come risultato l indirizzo della variabile creata Se P è una variabile di tipo puntatore a TipoDato, l istruzione: free(p) P = malloc(sizeof(tipodato)); assegna l indirizzo restituito dalla funzione malloc a P Rilascia lo spazio di memoria puntato da P Companies, srl 3
Stack e Heap Proc ( ).. int *Punt1; int **Punt2;... 5 Record di attivazione di... 3 Stack Heap Companies, srl 4
Rischi della gestione dinamica della memoria produzione di garbage : riferimenti fluttuanti (dangling references): Companies, srl 5
Lista dinamica Costruzione e gestione della struttura dinamica (pseudotipo astratto) lista mediante puntatori: Lista Elemento Puntatore 1 della a elemento lista 2 e1 e2 en Puntatore NULL Ultimo elemento Puntatore alla testa di lista testa di lista coda di lista Companies, srl 6
Dichiarazione lista dinamica (1) Invece di dichiarare il tipo lista, si dichiarano i suoi elementi: struct EL { }; TipoElemento Info; struct EL *Prox; typedef struct EL ElemLista; typedef ElemLista *ListaDiElem; Sintassi un po nuova: la prima dichiarazione del tipo strutturato struct EL definisce un primo campo, Info, del tipo TipoElemento e permette di dichiarare il campo Prox come puntatore al tipo strutturato che si sta definendo; la seconda dichiarazione utilizza typedef per rinominare il tipo struct EL come ElemLista; la terza dichiarazione definisce il tipo ListaDiElem come puntatore al tipo ElemLista. Companies, srl 7
Dichiarazione lista dinamica (2) Dichiarazione standard; mette in evidenza il tipo della lista: ListaDiElem Lista1, Lista2, Lista3; Dichiarazioni abbreviate: ElemLista *Lista1; se non interessa mettere in evidenza il tipo della lista, ma si vuole indicare esplicitamente il tipo dei suoi elementi. struct EL *Lista1 può sostituire entrambe le typedef se non è necessario nominare esplicitamente né il tipo della lista né il tipo dei suoi elementi. Companies, srl 8
Operazioni sulle liste: Inizializzazione (1) Assegna il valore NULL alla variabile testa della lista : l operazione: Inizializza (Lista): Lista Se però vogliamo eseguire l operazione in maniera parametrica: Companies, srl 9
Inizializzazione (2) #include <stdlib.h> void Inizializza (ListaDiElem *Lista) /* Lista è la variabile locale che punta alla "testa di lista". La funzione assegna alla testa di lista" il valore NULL corrispondente al valore di lista vuota */ { } *Lista = NULL; Lista L istruzione Inizializza(&Lista1); produce: Lista1 Al termine dell esecuzione, il parametro formale Lista viene eliminato Companies, srl 10
Inizializzazione (3) senza parametro #include <stdlib.h> ElemLista *Lista1; void Inizializza(void) { Lista1 = NULL; } Inizializzazione tramite accesso alla variabile globale Si raccomanda di evitare questa prassi! Companies, srl 11
Controllo di lista vuota boolean ListaVuota (ListaDiElem Lista) { } /* Produce il valore true se la lista passata come parametro è vuota, false in caso contrario, a Lista viene passato il valore contenuto nella variabile testa di lista. Lista punta pertanto al primo elemento della lista considerata */ if (Lista == NULL) return true; else return false; La chiamata sarà: ListaVuota(Lista1) Companies, srl 12
Ricerca di un elemento nella lista boolean Ricerca (ListaDiElem Lista, TipoElemento ElemCercato) { ElemLista *Cursore; } if (Lista!= NULL) { Cursore = Lista; /* La lista non è vuota */ while (Cursore!= NULL) { if (Cursore >Info == ElemCercato) return true; Cursore = Cursore >Prox; /* In questa maniera Cursore viene fatto puntare all'elemento successivo della lista */ } } return false; Companies, srl 13
Ricerca di un elemento nella lista, versione ricorsiva boolean Ricerca (ListaDiElem Lista, TipoElemento ElemCercato) { } if (Lista == NULL) return false; else if (Lista >Info == ElemCercato) return true; else return Ricerca(Lista >Prox, ElemCercato); Companies, srl 14
Estrazione della testa e della coda di una lista TipoElemento TestaLista (ListaDiElem Lista) /* È applicabile solo a liste non vuote. Se la lista è vuota segnala l'errore in modo opportuno; in caso contrario produce come risultato il valore del campo Info del primo elemento della lista */ ListaDiElem CodaLista (ListaDiElem Lista) /*Produce come risultato un puntatore alla sottolista ottenuta da Lista cancellandone il primo elemento. Essa non deve modificare il parametro originario. Anche questa assume l'ipotesi che il parametro passatole sia una lista non vuota */ CodaLista Lista Ultimo elemento e1 e2 en Companies, srl 15
Inserimento di un nuovo elemento in testa alla lista (1) Punt Lista e1 e2 en Punt = malloc(sizeof(elemlista)); Punt >Info = Elem; Punt Elem Lista e1 e2 en Companies, srl 16
Inserimento di un nuovo elemento in testa alla lista (2) Infine si collega il nuovo elemento al precedente primo elemento della lista e la testa della lista viene fatta puntare al nuovo elemento: Punt Elem Lista e1 e2 en Companies, srl 17
Inserimento di un nuovo elemento in testa alla lista (3) void InsercisciInTesta (ListaDiElem *Lista, TipoElemento Elem) { } ElemLista *Punt; /* Allocazione dello spazio necessario per la memorizzazione del nuovo elemento e inizializzazione del puntatore */ Punt = malloc(sizeof(elemlista)); Punt >Info = Elem; Punt >Prox = *Lista; *Lista = Punt; Lista Punt Elem Lista1 e1 e2 en Companies, srl 18
Inserimento di un nuovo elemento in coda alla lista void InserisciInCoda (ListaDiElem *Lista, TipoElemento Elem); { } ElemLista *Punt; if (ListaVuota (*Lista)) { } Punt = malloc(sizeof(elemlista)); Punt >Prox = NULL; Punt >Info = Elem; *Lista = Punt; else InserisciIncoda (&((*Lista) >Prox), Elem); Companies, srl 19
Lista*1 Lista*2 Lista*3 Lista*n Lista*n+1 e1 e2 en-1 en Lista1 Lista*1 Lista*2 Lista*3 Lista*n+1 Punt Elem Lista1 e1 e2 en-1 en Lista*1 Lista*2 Lista*3 Lista*n+1 Punt Elem Lista1 e1 e2 en-1 en Companies, srl 20
Cancellazione di un elemento dalla lista } - L elemento precedente al quello da cancellare viene collegato al successivo - Effettuo la free dell elemento da rimuovere Companies, srl 21
Riassumendo Strutture dati dinamiche = pseudotipi di dato astratti dinamici Realizzate mediante puntatori Puntatori: struttura di basso livello ---> a rischio Raccomandazione: usare i puntatori solo all interno delle operazioni astratte associate alle relative strutture Liste: primo e fondamentale -ma non unico!!- esempio di struttura dinamica Altri più complessi e potenti verranno visti in corsi successivi Una prima valutazione -a spanne- dell efficienza della struttura dinamica lista rispetto all array: Si evita lo spreco di memoria/rischio di overflow (obiettivo iniziale) A prezzo di un -lieve- aumento dovuto ai puntatori Da un punto di vista del tempo necessario all esecuzione degli algoritmi: pro e contro (inserire in testa meglio, inserire in coda peggio, però la ricerca in una lista ordinata non si può fare con algoritmi del tipo della ricerca in un vocabolario Il seguito alle prossime puntate (corsi). Companies, srl 22