MODULO STRUTTURE DATI FONDAMENTALI: Strutture dinamiche classe 4° INDUSTRIALE INFORMATICA Focus on 1 Implementazione di strutture lineari E’ possibile implementare una struttura dati lineare in modo: statico (tramite Array) dinamico (tramite una successione di record collegati tra loro per mezzo di puntatori) 2 Limiti dell’allocazione statica della memoria gli array OCCUPAZIONE DI MEMORIA: sovradimensionamento della struttura dovuto alla difficoltà di stima a priori VELOCITÀ IN ESECUZIONE: rigidità nelle operazioni di inserimento e cancellazione 3 Ud1. STRUTTURE DATI DINAMICHE Le Liste semplici Una lista consente di memorizzare dati in modo dinamico, cioè all’occorrenza nel programma Richiamo: un puntatore rappresenta l’indirizzo di memoria della variabile puntata. Si possono definire puntatori a variabile di tipo intero, reale ma anche a variabili strutturate come ad esempio a record. Def: una lista semplice è una successione di record costituiti da due o più campi di cui uno sicuramente di tipo puntatore e gli altri di tipo informativo. L’elemento generico è il record “vagone” cha ha almeno due campi “scomparti” ed uno di essi è il puntatore “gancio” che consente il collegamento agli altri vagoni 4 Creazione di una lista L’operazione di creazione lista prevede: 1. la definizione della struttura, 2. la dichiarazione di un puntatore globale “motrice” che regge tutti gli altri vagoni 3. la creazione di un nuovo elemento che si deve attaccare alla motrice 5 Creazione di una lista in C++ MOTRICE VAGONE INFO PROX X …… struct vagone NUOVO {int info; struct vagone * prox}; struct vagone * motrice=NULL; /*Inizial.*/ … void CreaLista (int x) {struct vagone * nuovo=NULL; /*Inizial.*/ nuovo=new(struct vagone); /*allocazione nuovo vagone */ nuovo->info=x; /* accesso ed assegnazione al campo info */ nuovo->prox=NULL; motrice=nuovo; } 6 Inserimento in testa Nell’inserimento in testa si deve collegare un nuovo record in prima posizione ossia deve essere puntato dalle motrice. Il collegamento che va realizzato per primo è quello del nuovo record con il resto della lista. Successivamente si può staccare la motrice e farla puntare al nuovo record 7 Inserimento in testa in C++ MOTRICE X A B C NUOVO … void InsTesta (int x) {struct vagone * nuovo=NULL; /*Inizial.*/ nuovo= new(struct vagone); nuovo->info=x; nuovo->prox=motrice; motrice=nuovo; } 8 Inserimento in coda In questa funzione scorro tutta la lista fino a quando non trovo l’ultimo vagone a questo attacco il nuovo 9 Inserimento in coda in C++ NUOVO MOTRICE X A B C APP … void InsCoda (int x) {struct vagone * nuovo=NULL; struct vagone * app=NULL; nuovo= new(struct vagone); nuovo->info=x; nuovo->prox=NULL; if (motrice==NULL)/* la lista è vuota */ InsTesta(x); /* chiamata alla funzione */ else { app=motrice; while (app->prox !=NULL) app=app->prox; app->prox=nuovo; }} 10 Inserimento in un punto qualunque con condizione Per inserire un nuovo vagone in una posizione qualunque con il rispetto di una condizione abbiamo bisogno di un puntatore che: 1. scorra la lista 2. trovi la posizione 3. realizzi i collegamenti 11 Inserimento in un punto qualunque con condizione in C++ MOTRICE A B C … void InsQlq (int x) {struct vagone * nuovo=NULL; APP struct vagone * app=NULL; nuovo= new(struct vagone); NUOVO X nuovo->info=x; nuovo->prox=NULL; if (motrice->info==(condizione)) { nuovo->prox=motrice; /*inserimento in testa*/ motrice=nuovo;} else { app=motrice; while((app->prox!=NULL)&&((app->prox->info) !=(condizione)) app=app->prox; if (app-> prox==NULL) cout<<“\n Elemento non inseribile condizione non verificata”; else{ nuovo->prox=app->prox; app->prox=nuovo; } } } 12 Cancellazione in testa La cancellazione di un record “vagone” in testa si effettua facendo scorrere in avanti di una struttura (vagone) il puntatore che punta tutto il treno (motrice). 13 Cancellazione in testa In C++ MOTRICE A B C D … Void DropTesta () { } motrice=motrice->prox; 14 Cancellazione in coda Cancellare l’ultimo vagone della coda presuppone lo scorrimento di un puntatore d’appoggio che determina il vagone terminale della lista per interrompere tale collegamento 15 Cancellazione in coda in C++ MOTRICE A … B C APP Void DropCoda () { struct vagone * app=NULL; if (motrice->prox==NULL) motrice=NULL; else{ app=motrice; while(app->prox->prox !=NULL) app=app->prox; app->prox=NULL; } } MOTRICE X 16 Cancellazione in un punto qualunque con condizione Per cancellare un vagone in un punto qualunque abbiamo bisogno di un puntatore che: 1. scorra la lista 2. trovi il vagone da cancellare 3. realizzi i vari collegamenti 17 Cancellazione in un punto qualunque con condizione in C++ MOTRICE A … B C D APP Void DropQlq () {struct vagone * app=NULL; if ((motrice->prox==NULL) && (motrice->info==(Condizione)) DropTesta(); /* chiamata alla funzione */ else{ app=motrice; while((app->prox !=NULL) && (app->prox->info!= Condizione)) app=app->prox; if (app->prox==NULL) cout<<“\n condizione non verificata da alcun elemento”; else app->prox=app->prox->prox; } } 18 Confronto tra struttura statica di array e struttura dinamica di lista Si può osservare che: - entrambe sono costituite da elementi omogenei tra loro le componenti dell’array sono solitamente di un tipo standard definito dall’utente, gli elementi della lista sono sempre formati da una o più parti informative e da una di tipo puntatore - la lista consente dimensioni variabili, mentre l’array richiede una dimensione prefissata - L’accesso all’array avviene mediante l’indice della componente, l’accesso agli elementi della lista comporta lo scorrimento degli elementi con un puntatore inizialmente posizionato sulla testa che viene successivamente spostato tramite i puntatori 19 Vantaggi e svantaggi dell’impiego della lista rispetto all’array • Con la lista vi è una maggiore occupazione di memoria dovuta alla presenza di puntatori e lo svantaggio di una minore semplicità di uso • Il vantaggio dell’uso di una lista sta nel poter effettuare su di essa in modo più rapido le operazioni di inserimento ed eliminazione dei dati 20 Verifica delle conoscenze acquisite: Test vero/falso V F Un nodo in una lista è un’ unità atomica di informazione Il valore NULL assegna ad un puntatore il valore zero Un puntatore contiene l’indirizzo di memoria della variabile puntata L’aggettivo lineare, riferito ad una lista semplice significa che tutti i nodi della lista hanno un predecessore ed un successore La lista e una struttura dati statica Le variabili dinamiche vengono dichiarate in testa al programma L’elemento generico di una lista semplice è costituito da un record che ha almeno due campi di cui uno puntatore Se voglio inserire un nuovo elemento in una lista sicuramente dovrò creare una nuova struttura dove inserirlo e poi ricercare la posizione dove collocarlo 21 Esercizi di applicazione proposti per casa mirati all’acquisizione delle competenze 1) Scrivere la funzione di visualizzazione che legge gli elementi di una lista, a partire dal primo, seguendo l’ordine dei puntatori. 2) Fornire la dichiarazione di una lista con puntatori per memorizzare un elenco ordinato di nomi e città. 3) Utilizzando la struttura dinamica costruita nell’esercizio precedente, costruire una funzione che dopo aver acquisito da tastiera un nome, lo ricerchi nella lista: se lo trova visualizza la città corrispondente, altrimenti scrive un messaggio di non trovato. ... da realizzare successivamente in laboratorio 22 Esercizio di applicazione proposto per casa mirato all’acquisizione delle capacità Costruire una rubrica telefonica che contenga, per ciascuna persona, il nome, il cognome, e il numero di telefono. Tale rubrica dovrà essere gestita con una lista. Si deve prevedere un menù di scelta che consenta all’utente di scegliere tra le seguenti funzioni in modo ripetuto: -Una funzione di inserimento di una nuova persona in ordine alfabetico rispetto al cognome; -Una funzione di ricerca per cognome che stampi il numero di telefono; -Una funzione di cancellazione dalla rubrica. ... da realizzare successivamente in laboratorio 23 STRUTTURE DATI FONDAMENTALI: Le Code Una coda è una struttura logica che segue una politica di tipo FIFO (First in First out). Per gestire una coda sono necessarie almeno tre funzioni: push pop codavuota. La coda a livello d’implementazione è una lista in cui l’inserimento si effettua sulla fine e l’estrazione sull’inizio. 24 STRUTTURE DATI FONDAMENTALI: Le Code in C++ elecoda … /* definizione dell’elemento della coda */ struct elecoda{ int info; struct elecoda * prox; }; info prox queue INIZIO FINE … struct coda{ struct elecoda * inizio; struct elecoda * fine; }; struct coda queue; /* variabile globale */ queue.inizio= NULL; /*inizializzazione*/ queue.fine= NULL; ... 25 Inserimento La funzione d’inserimento in coda PUSHCODA crea un nuovo record nel quale inserisce la nuova informazione e lo attacca alla fine della coda. Si utilizza anche una funzione booleana CODAVUOTA che ci dice se la coda ha o meno elementi 26 Inserimento in C++ NUOVO X A B C queue INIZIO FINE void pushcoda (int x) {struct elecoda * nuovo=NULL; nuovo = new( struct elecoda); /*allocazione*/ nuovo->info=x; … nuovo->prox=NULL; NUOVO x if (codavuota() ) bool codavuota () { queue.inizio=nuovo; { ifqueue queue.fine= nuovo;} (queue.inizio==queue.fine==NULL) else INIZIO return true; { queue.fine-> prox = nuovo; FINE queue.fine=queue.fine-> prox; return false;} }} 27 ... Cancellazione La cancellazione elimina il primo elemento della lista gestita come coda buttando fuori il valore. 28 Cancellazione in C++ EMERGENTE A B C queue INIZIO FINE ... int popcoda() { int emergente; emergente=queue.inizio->info; queue.inizio=queue.inizio->prox; return emergente; } 29 STRUTTURE DATI FONDAMENTALI: Le Pile Una pila e una struttura logica che segue una politica di tipo LIFO ( Last in First out). Per gestire una pila sono necessarie almeno tre funzioni: push pop pilavuota La pila a livello d’implementazione è una lista in cui sia l’inserimento che 30 l’estrazione si effettuano sulla fine e l’estrazione sulla testa STRUTTURE DATI FONDAMENTALI: Le Pile in C++ elepila info prox TESTA … /* definizione dell’elemento della pila */ struct elepila{ int info; struct elepila * prox; }; struct elepila * testa =NULL; /* inizializzazione*/ 31 Inserimento La funzione d’inserimento in coda PUSHPILA crea un nuovo record nel quale inserisce la nuova informazione e lo attacca in testa alla pila. Si utilizza anche una funzione booleana PILAVUOTA che ci dice se la 32 pila ha o meno elementi Inserimento in C++ NUOVO A X B C TESTA ..... void pushpila (int x) {struct elecoda * nuovo=NULL; nuovo = new( struct elepila); *allocazione*/ nuovo->info=x; nuovo->prox=NULL; …NUOVO if ( pilavuota()) bool pilavuota () testa=nuovo; else { if (testa==NULL) TESTA { nuovo-> prox = testa; return true; return false; testa=nuovo; } } } x 33 Cancellazione La cancellazione elimina il primo elemento della lista gestita come pila buttando fuori il valore. 34 Cancellazione in C++ EMERGENTE A B C TESTA .... int poppila() { int emergente; emergente=testa->info; testa=testa->prox; return emergente; } 35