Cesare Rota. Programmare con C++

Похожие документы
INTRODUZIONE ALLA PROGRAMMAZIONE

Gestione di files Motivazioni

Esercizi Strutture dati di tipo astratto

Il linguaggio C. Puntatori e dintorni

Problema: dati i voti di tutti gli studenti di una classe determinare il voto medio della classe.

Pr1: determinare il maggiore di n numeri interi n. Fondamenti di Informatica Prof. Vittoria de Nitto Personè

Laboratorio di Informatica

Strutture dati e loro organizzazione. Gabriella Trucco

Laboratorio di Informatica

Esercizio 2: Algebra dei Puntatori e Puntatori a Puntatori

La classe std::vector della Standard Template Library del C++

Informatica 1. Prova di recupero 21 Settembre 2001

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

ADT: Abstract Data Type. Quasi ADT. ADT per collezioni di dati (code generalizzate) 04 I tipi di dati astratti (I parte)

Questa soluzione va contemplata quando le lunghezze stimate dalle liste usate sono significativamente maggiori delle dimensioni di un elemento.

Le basi del linguaggio Java

LE STRUTTURE DATI DINAMICHE: GLI ALBERI. Cosimo Laneve

La struttura dati CODA

INFORMATICA. Strutture iterative

STRUTTURE DI CONTROLLO DEL C++

Algoritmi e Strutture Dati

Università degli Studi di Cassino Corso di Fondamenti di Informatica Tipi strutturati: Stringhe. Anno Accademico 2010/2011 Francesco Tortorella

Esercitazione 6. Array

Alberi ed Alberi Binari

Liste con sentinella. intlist *createlist(void){ intlist *q = malloc(sizeof(intlist)); if(!q) { exit(-1); } q->next = q->prev = q; return q; }

LABORATORIO DI PROGRAMMAZIONE 1 CORSO DI LAUREA IN MATEMATICA UNIVERSITÀ DEGLI STUDI DI MILANO III Indice

Primi passi col linguaggio C

Gestione dinamica della memoria

Variabili. Unità 2. Domenico Daniele Bloisi. Corso di Programmazione e Metodi Numerici Ingegneria Aerospaziale BAER

Strutture di Controllo

in termini informali: un algoritmo è una sequenza ordinata di operazioni che risolve un problema specifico

Le strutture di controllo in C++

Linguaggio C: le funzioni. Visibilità variabili e passaggio parametri

Perché il linguaggio C?

Strutture Dinamiche. Fondamenti di Informatica

Scrittura formattata - printf

Introduzione alla programmazione

PILE E CODE. Pile (stack):

Allocazione Dinamica della Memoria

Esercitazione 4. Comandi iterativi for, while, do-while

Non ci sono vincoli sul tipo degli elementi di un vettore Possiamo dunque avere anche vettori di

Linguaggio C: PUNTATORI

Funzioni, Stack e Visibilità delle Variabili in C

Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE. Francesco Tura. F. Tura

Il tipo astratto coda con priorità: specifiche sintattiche e semantiche. Realizzazioni.

Linguaggi di programmazione - Principi e paradigmi 2/ed Maurizio Gabbrielli, Simone Martini Copyright The McGraw-Hill Companies srl

Algoritmi di ordinamento: Array e ricorsione

Algoritmi, Strutture Dati e Programmi. UD 2.b: Programmazione in Pascal

Breve Manuale di Riferimento sulla Sintassi Linguaggi C++ e FORTRAN

Esercizio 1: funzione con valore di ritorno di tipo puntatore

Ogni variabile in C è una astrazione di una cella di memoria a cui corrisponde un nome, un contenuto e un indirizzo.

Parametri Formali di una Funzione e Record di Attivazione

Lezione 21 e 22. Valentina Ciriani ( ) Laboratorio di programmazione. Laboratorio di programmazione. Lezione 21 e 22

18 - Vettori. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Stringhe e allocazione dinamica della memoria

Programmazione I - Laboratorio

Algoritmi di Ricerca. Esempi di programmi Java

Esercitazione: Implementazione in linguaggio C dell ADT. Stack con l utilizzo. di linked list

Struttura dati astratta Coda

#include <iostream> // libreria che gestisce flusso di input e output. using namespace std; // uso di librerie standard del C++

Strutture Dati Dinamiche

Cos è un algoritmo. Si dice algoritmo la descrizione di un metodo di soluzione di un problema che sia

Unità Didattica 4 Linguaggio C. Vettori. Puntatori. Funzioni: passaggio di parametri per indirizzo.

La scrittura di un programma Modellizzazione del programma Scrittura del codice Esercizi. Sperimentazioni I. Alberto Garfagnini, Marco Mazzocco

Laboratorio di Algoritmi e Strutture Dati. Code con Priorità

La scrittura di un programma Modellizzazione del programma Scrittura del codice Esercizi. Sperimentazioni I. Alberto Garfagnini, Marco Mazzocco

Costanti e Variabili

I PUNTATORI E LE STRUTTURE DATI DINAMICHE. Cosimo Laneve/Ivan Lanese

La Gestione della Memoria. Carla Binucci e Walter Didimo

PROGRAMMAZIONE: Le strutture di controllo

Транскрипт:

Cesare Rota Programmare con C++ Questo fascicolo deve essere allegato al volume Programmare con C++ di Cesare Rota ISBN 978-88-203-4248-7, ne è parte integrante e non può essere venduto separatamente EDITORE ULRICO HOEPLI MILANO

Indice Strutture dinamiche di dati 3 I atori 3 Lista 6 La pila 7 La coda 13 Lista ordinata 15 2

I atori Strutture dinamiche di dati L uso degli array comporta una limitazione che consiste nel disporre di un numero fisso di posti. Ovviamente in molti problemi questa limitazione non è accettabile, quando la dimensione dell array deve cambiare durante l esecuzione del programma. Per superare queste limitazioni, nei linguaggi di programmazione è stata introdotta la possibilità di definire strutture dinamiche di dati, cioè strutture alle quali viene assegnato lo spazio necessario in memoria centrale soltanto quando e se serve durante l esecuzione del programma. Le tecniche di programmazione per la gestione dinamica delle strutture di dati si basano su meccanismi e funzioni che utilizzano un nuovo tipo di dato, il atore, e che consentono di allocare e di togliere lo spazio di memoria assegnato ad un dato; inoltre la gestione complessiva della memoria risulta più efficiente in quanto gli spazi assegnati non devono essere necessariamente contigui. Una variabile atore è un indirizzo che permette di accedere ad un'altra variabile, così come un numero di telefono permette di raggiungere una persona. Il valore della variabile non è di per sé importante, mentre lo è il contenuto della variabile ata. Il tipo atore definisce variabili del linguaggio C++ dalle caratteristiche molto particolari. Esempio Puntatore Il seguente programma presenta un breve esempio sull uso di un atore, e contiene tutte le procedure e le notazioni necessarie al suo impiego. Codice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <cstdlib> #include <iostream> using namespace std; int main () Puntatore.cpp //definisce la variab. q come un atore ad un intero int* q; // inizializza q q = NULL; // q è vuoto // assegna a q l'indirizzo di un'area di memoria contenente un int q = new int; // assegna 10 al atore *q = 10; // scrivi il contenuto di *q cout << *q; // elimina lo spazio ato da q. q resta vuoto; delete q; 3

Programmare con C++ 24 25 26 27 28 29 30 } // scrivi due righe vuote cout << "\n\n"; // arresta esecuzione e termina programma system ("pause"); return 0 ; Altri esempi di definizione di tipo atore sono: double *pdouble; bool *pbool; char *pchar; Analisi del codice Alla riga 8 viene definita la variabile q che, all interno del programma, è in grado di contenere l indirizzo di un area di memoria adatta a contenere un intero. L istruzione di riga 11 del programma è l inizializzazione del atore q; come tutte le variabili anche q ha bisogno di essere inizializzata prima di essere utilizzata. Il valore NULL è un valore particolare che significa nulla : un atore che vale NULL non a alcuna variabile, ma possiede un valore definito. All inizio dell esecuzione i atori sono indefiniti, cioè contengono valori non determinati. Se si tenta di leggere il contenuto di un atore indefinito, si può ottenere un valore imprevedibile, ma se si tenta di scriverlo si possono causare errori in esecuzione. Infatti il atore indefinito contiene un indirizzo di memoria casuale e non è esclusa la possibilità che tale indirizzo corrisponda alla posizione di altre variabili o al codice stesso del programma. Se un programma che tratta atori fornisce, durante l esecuzione, risultati diversi da quelli attesi è probabile che stia lavorando con qualche atore indefinito. Alla riga 14 la funzione new riserva un area destinata a contenere la variabile ata. L operatore new esegue l'operazione di allocazione della memoria necessaria a contenere una variabile del tipo ato: nel caso dell'esempio una variabile intera. L allocazione consiste nel trovare uno spazio di memoria libero, grande a sufficienza per contenere la variabile richiesta, e quindi ad occuparlo, segnalando tale spazio come non disponibile per altri usi. Tutte le variabili ate trovano lo spazio necessario in un'area apposita, chiamata heap (letteralmente, mucchio). Le variabili ate vengono chiamate variabili dinamiche in conseguenza del fatto che esse vengono generate durante l'esecuzione del programma, apo in modo dinamico. Successivi utilizzi dell operatore new occupano spazi differenti dell area di heap, fino eventualmente a riempirla. La riga 23 del programma utilizza l operatore delete q;, che annulla l effetto di New, liberando la memoria occupata dalla variabile e rendendola disponibile per altri usi. Se si tenta di eseguire questa procedura usando un atore a NULL o un atore indefinito si ha un errore in esecuzione. Esempio PuntatoreA Di seguito viene presentato un programma che usa di proposito un atore indefinito; 4

Strutture dinamiche di dati Codice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <cstdlib> #include <iostream> using namespace std; int main () } atorea.cpp //definisce la variab. q come un atore ad un intero int* q; // scrive *q, senza inizializzarlo cout << *q; // scrivi due righe vuote cout << "\n\n"; // arresta esecuzione e termina programma system ("pause"); return 0 ; se si esegue il programma precedente, si ottiene la visualizzazione del seguente messaggio di errore generato dall istruzione di riga 11. Si è verificato un errore in atorea.exe. L'applicazione verrà chiusa. Prima di approfondire ulteriormente l argomento, riassumiamo in breve i concetti principali esposti: i atori sono variabili che permettono di generare ed accedere a variabili di un tipo assegnato durante l'esecuzione di un programma; le variabili così ottenute si chiamano variabili dinamiche; il valore NULL può essere assegnato a qualsiasi atore per indicare che non a a nulla; con la procedura q = new int; si crea una variabile dinamica, con delete la si distrugge. Volendo definire un atore ad una variabile di tipo non elementare, come un array o un record, si deve operare come nell esempio che segue: struct UnaStruttura int c1 ; char c2 ; }; UnaStruttura *p; p= new UnaStruttura; p->c1 = 10; Nel codice precedente è definita una struttura che contiene due membri: c1 e c2; l ultima istruzione mostra come accedere a un membro della struttura. L operatore -> permette l accesso al singolo membro di un struttura. 5

Programmare con C++ Nel codice precedente il valore 10 viene assegnato solo a c1. Lista La lista semplice è un insieme di elementi composti da un'informazione e da uno o più atori ad altri elementi dello stesso tipo; si dice nodo un elemento della lista: ogni nodo è una struttura, costituita da uno o più campi contenenti informazioni, e da un campo atore contenente l'indirizzo del nodo successivo; il primo nodo è indirizzato da un atore ( Testa della lista); il campo atore dell ultimo elemento contiene NULL. La lista è una insieme di dati, formato da elementi dello stesso tipo collegati in catena, la cui lunghezza varia dinamicamente. La struttura del singolo elemento (informazione + atore) suggerisce per esso l uso delle strutture (struct): in essa alcuni campi sono destinati alle informazioni, ed un altro al atore. testa fondo NU LL Per realizzare una lista usando i atori espliciti occorre definire il tipo di oggetti che compongono la lista (nodi). Per esempio: Nodo Punt 6

Strutture dinamiche di dati struct Nodo int ; Nodo * ; }; Nodo * Primo; Tra le strutture dinamiche assumono particolare importanza le strutture dette pila e coda. Come si vedrà nelle pagine successive per questi due insiemi di dati è possibile presentare un esempio tratto dalla vita di tutti giorni e un esempio ricavato dalle funzioni definite nella maggior parte dei sistemi operativi attualmente in uso. Le strutture di cui parliamo vengono definite in modo astratto attraverso le funzioni che possono essere attivate su ciascun insieme di dati. La pila Possiamo definire la struttura di pila in astratto, descrivendo le uniche procedure che possono operare su di essa e non ammettendo altri tipi di intervento. La pila può essere considerata come un elenco ordinato nel quale si può aggiungere un elemento con la funzione detta Push e dal quale può essere estratto un elemento con una procedura detta Pop. La regola di funzionamento della pila è: l'ultimo elemento inserito con un push è il primo elemento ad essere estratto con un pop. Per evidenziare il funzionamento della struttura a pila, essa viene spesso chiamata struttura LIFO, acronimo di Last In First Output, ovvero l'ultimo ad entrare è il primo ad uscire. Consideriamo un esempio tratto dalla vita quotidiana e pensiamo a che cosa si può fare con una pila di piatti: su di essa si può aggiungere in testa un nuovo piatto (push) e da essa si può levare un piatto (pop) sempre solo dalla testa. Viene illustrata, ora, un importante applicazione della pila nell ambito della gestione di un sistema di elaborazione. Quando nell esecuzione di un programma si incontra una richiesta di cedere il controllo a una funzione (con terminologia meno accurata, ma più comprensibile si può anche dire: quando nell esecuzione di un programma si incontra una richiesta di salto a una funzione ), occorre memorizzare il o in cui tornare una volta che la funzione sia stata eseguita. Questo o viene detto indirizzo di rientro. Se nella funzione si incontra un altro salto simile, occorre memorizzare un secondo indirizzo di rientro e così via. Quando una funzione termina, il rientro deve avvenire all ultimo o memorizzato per proseguire l elaborazione nell unità (programma o funzione) che aveva richiesto l ultimo salto a funzione. Gli indirizzi di rientro seguono, perciò, la logica di funzionamento della pila e possono quindi utilmente essere memorizzati in una struttura dati di questo tipo. 7

Programmare con C++ Esempio CreaPila Inserire in una pila una serie di numeri naturali dati in input. La serie termina con il numero zero. Indicazioni per la soluzione L esempio richiede la creazione di una pila: tale creazione comporta l operazione di inserimento in testa (PUSH) dei dati, di volta in volta, letti da tastiera; poiché i dati digitati sono una sequenza di numeri interi, come richiede il testo dell esempio, si tratta di creare una pila di numeri naturali. Quindi l algoritmo richiesto è formato principalmente da una struttura di controllo MENTRE dove, per ogni numero intero inserito, vengono ripetute le seguenti operazioni 1. Leggi un numero. 2. Crea un nuovo nodo con l informazione da inserire. 3. Collega il nuovo elemento al primo elemento della lista. 4. Aggiorna il atore di testa della lista a are al nuovo elemento. Le operazioni indicate sopra vengono presentate con uno schema grafico allo scopo di fare maggiore chiarezza su come si può operare con i atori (vedi pag. successiva). Crea atore Nuovo a nuovo Nodo Testa Nuo vo Assegna a il valore letto N ; assegna al atore del nuovo nodo il valore di testa. Nuo vo N NU LL Aggiorna il atore di testa della lista a are al nuovo elemento. Testa N NU LL Pseudocodifica // Struttura dati Nodo int atore a Nodo pun } Funzione Push (Testa) Aggiunge dati in testa alla lista crea nodo Nuovo Assegna N a di Nuovo Assegna Testa a pun di Nuovo Aggiorna il atore di testa della lista a are al nuovo elemento. 8

Strutture dinamiche di dati FINE Push INIZIO Definisci Testa come atore a Nodo Inizializza Testa a NULL chiedi e leggi intero N MENTRE N!= 0 Richiama Push(Testa) chiedi e leggi intero N FINE MENTRE FINE Dalla pseudocodifica precedente viene sviluppato soltanto il codice relativo alla funzione Push; anche per tutti gli esempi successivi lo schema del programma principale resterà inalterato e verrà presentato solo il codice della funzione in esame. Codice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19..... struct Nodo int ; Nodo * pun; }; int N; void Push(Nodo* &Testa, int N) } Prova di esecuzione Nodo * Nuovo; Nuovo = new Nodo; Nuovo-> = N; Nuovo->pun = Testa; Testa = Nuovo; Push.cpp 9

Programmare con C++ Poiché l esempio non richiede la visualizzazione dei risultati, per avere una prova di esecuzione significativa si rimanda all esempio successivo. Analisi del codice Il codice è relativo alla sola funzione Push: dalla riga 13 alla 17 si sviluppa la funzione che serve per inserire in testa alla pila un nuovo nodo; alle righe 13,14 viene creato un nuovo nodo ato dal atore Nuovo; le righe 15,16 completano i dati della struttura Nuovo; nella riga 15 a viene assegnato il numero letto in input e nella riga 16 al atore viene assegnato l indirizzo di testa della pila. La riga 17 aggiorna il atore di testa della lista a are al nuovo elemento. Esempio CreaStampaPila Visitare la lista dall inizio alla fine e per ogni elemento scrivere su video il membro Indicazioni per la soluzione Tutti nodi della lista devono essere elaborati: in questo caso l elaborazione consiste solo nella scrittura del dato contenuto nel nodo. Quando una elaborazione viene estesa a tutti i nodi di una struttura dinamica si parla di visita della struttura Pseudocodifica // Struttura dati Nodo int atore a Nodo pun } Funzione StampaLista (Testa) Definisci atore p Assegna a p il valore di Testa MENTRE pila non finita Scrivi dato Passa a nodo successivo FINE MENTRE FINE StampaLista //p!= NULL Codice StampLista.cpp 1 void StampaLista(Nodo * Testa) 2 3 cout<<"\n\ninizio stampa \n"; 4 Nodo * p; 5 p = Testa; 6 while (p!= NULL) 7 8 cout <<"\t"<< p-><<" \n"; 9 p = p->pun; 10 } 11 cout<<"fine stampa \n"; 12 } 10

Strutture dinamiche di dati Analisi del codice La funzione di stampa è costituita principalmente da una ripetizione MENTRE e la visita della struttura avviene utilizzando un atore p che, alla riga 5, è inizializzato a Testa. Le righe che vengono ripetute sono la 8 e la 9: la prima scrive il contento di, la seconda incrementa il atore per passare al nodo successivo; la ripetizione si arresta quando il atore risulta = NULL (riga 6). Prova di esecuzione Esempio PopPila Data una lista non vuota realizzare una funzione che elimina il primo elemento di testa (pop) Indicazioni per la soluzione Il problema da risolvere si configura nel seguente modo: Se la lista non è vuota si aggiorna il atore di testa della lista o, per meglio dire, si assegna a Testa il atore al nodo successivo. Pseudocodifica Funzione Pop (Testa) Chiedi (vuoi togliere il primo nodo dalla lista? (s/n)) MENTRE Risp = s SE la lista non è vuota (Testa!= NULL) assegna a Testa il atore al nodo successivo Chiedi (vuoi togliere un altro nodo dalla lista? (s/n)) FINE MENTRE FINE Pop Lo schema che segue offre una rappresentazione grafica di quanto deve essere realizzato dalla funzione richiesta nell esempio. 11

Programmare con C++ testa POP testa fondo fondo NU LL NU LL Codice Pop.cpp 1 void Pop (Nodo * &Testa) 2 3 char r = 's'; 4 cout << "\nvuoi togliere il primo nodo dalla lista? (s/n)"; 5 cin >> r; 6 while (r == 's') 7 8 if (Testa!= NULL) 9 Testa = Testa->pun; 10 cout << "vuoi togliere un altro nodo? (s/n)"; 11 cin >> r; 12 } 13 } Prova di esecuzione 12

Strutture dinamiche di dati Analisi del codice La riga 9 è l elemento risolutore della funzione: aggiorna il atore Testa in modo che i al nodo successivo. Tale operazione viene fatta solo se la pila non è vuota. La coda Possiamo definire la struttura di coda in astratto, descrivendo le uniche funzioni che possono operare su di essa e non ammettendo altri tipi di intervento. La coda può essere considerata come un elenco ordinato nel quale si può aggiungere un elemento con la procedura detta Accoda e dal quale può essere estratto un elemento con una procedura detta Pop. La regola di funzionamento della coda è: l'ultimo elemento inserito con un Accoda è l ultimo elemento ad essere estratto con un pop. Per evidenziare il funzionamento della struttura a coda, essa viene spesso chiamata struttura FIFO, acronimo di First In First Output, ovvero il primo a entrare è il primo ad uscire. Consideriamo un esempio tratto dalla vita quotidiana e pensiamo a quale è la dinamica di una coda di persone davanti allo sportello di un ufficio: se tutte le persone della coda si comportano in modo corretto (evento rarissimo), quando il primo della coda ha terminato le proprie pratiche allo sportello, si allontana da essa (pop); se arriva una nuova persona, si mette in coda (si accoda). Con lo stesso criterio viene chiamata struttura FIFO (First In First Out, che significa il primo entrato è il primo ad uscire) una struttura nella quale, in senso figurato, i dati entrano da una parte ed escono dalla parte opposta. pop accoda sportello La struttura FIFO viene chiamata anche coda proprio perché funziona nello stesso modo. Così come si usa dire impilare o accatastare riferendosi alle pile, si dice accodare riferendosi alle code. Viene illustrata, ora, un importante applicazione della coda nell ambito della gestione di un sistema di elaborazione. Lavorando sui computer multiutente è frequente che si accodino stampe o lavori nelle rispettive code: i moduli software del sistema operativo che gestiscono queste attività del sistema di elaborazione seguono infatti il principio FIFO, per cui se più utenti richiedono le stampe sulla stessa stampante, esse vengono eseguite nello stesso ordine con cui sono state richieste (coda di SPOOL). L esempio che segue mostra la struttura della funzione Accoda, funzione che caratterizza la PILA; come già detto, questa funzione aggiunge un elemento a una lista facendo in modo che la gestione dei nodi segua il criterio First In First Output (FIFO). Esempio Accoda Accodare un nuovo nodo a una lista data Indicazioni per la soluzione Quelle che seguono sono le operazioni principali per realizzare l accodamento di un nuovo nodo a una lista: 13

Programmare con C++ 1. Visita della lista fino ad individuare l ultimo nodo (definire il atore Fondo come atore all ultimo nodo). 2. Creazione di un nuovo nodo con le informazioni da aggiungere. 3. Collegamento dell ultimo nodo al nuovo nodo appena creato. Pseudocodifica Funzione Accoda (Fondo, Testa, N) //Aggiunge dati in coda Cerca l ultimo elemento della lista e aggiorna il atore Fondo crea nodo Nuovo Assegna N a di Nuovo Assegna Testa a pun di Nuovo Se lista vuota // Se (Testa = = NULL) ALLORA Aggiorna il atore di testa della lista a are al nuovo elemento ALTRIMENTI Aggiorna il atore Fondo a are al nuovo elemento FINE Accoda Codice Accoda.cpp 1 void Accoda(Nodo* &Fondo, Nodo * &Testa,int N) 2 3 Nodo* p; 4 Nodo* q; 5 6 for (q = Testa; q!= 0; q = q->pun) 7 Fondo = q; 8 q = new Nodo; 9 q-> = N; 10 q->pun = 0; 11 if (Testa == NULL) 12 Testa = q; 13 else 14 Fondo->pun = q; 15 } Prova di esecuzione 14

Strutture dinamiche di dati Analisi del codice Nelle righe 3 e 4 vengono definiti due nuovi atori locali. La riga 6 serve per visitare l intera lista e individua il atore all ultimo elemento (atore Fondo). La riga 9, assegna N a di Nuovo, la riga 10 assegna Testa al atore di Nuovo. La riga 11 controlla che la lista non sia vuota: SE lista vuota, ALLORA Aggiorna il atore di testa della lista a are al nuovo nodo (riga 12), ALTRIMENTI Aggiorna il atore Fondo a are al nuovo nodo (riga 14). Lista ordinata Esempio ListaOrdinata Definire una funzione che sia in grado di inserire un numero dato in input in una lista ordinata. Indicazioni per la soluzione In primo luogo vengono presentati in modo sintetico i passi da eseguire per realizzare quanto richiesto alla funzione: 1. Visita la lista finché si incontra un nodo contenente nel campo un valore maggiore di quello da inserire oppure si incontra la fine della lista. 2. Crea un nuovo nodo con l informazione da inserire. 3. Inserisci il nuovo elemento. Pseudocodifica Funzione Inserimento (Testa, N) definisci p, q, Nuovo come atori a Nodo ricerca nella lista il nodo che contiene l intero minore dell intero da inserire salva in p e in q l indirizzo di tale nodo crea nodo Nuovo compila i suoi campi SE la lista q a alla testa ALLORA aggiorna Testa ALTRIMENTI aggiorna l indirizzo del atore del nodo trovato FINE Inserimento Codice 1 2 3 4 5 6 7 8 9 10 11 12 13 Inserimento.cpp void Inserimento(Nodo* &Testa,int N) Nodo * p = 0; Nodo * q; Nodo * Nuovo; for (q = Testa; q!= 0 && q-> < N; q = q->pun) p = q; Nuovo = new Nodo; Nuovo-> = N; Nuovo->pun = q; // controlla se si deve inserire in testa if (q == Testa) Testa = Nuovo; 15

Programmare con C++ 14 15 16 } else p->pun = Nuovo; Analisi del codice Alle righe 3,4,5 vengono definiti tre atori p, q e Nuovo: i primi due sono di lavoro, il terzo serve, come negli esempi precedenti, a creare il nuovo nodo da inserire nella lista. La riga 6 è la più complessa e serve per visitare la lista e per cercare il nodo prima del quale aggiungere il nuovo che contiene l intero acquisito da tastiera, essa è formata da una struttura for che necessita di una descrizione accurata: si tratta di una visita della lista che inizia dalla testa (prima istruzione: q = Testa;) e si sposta nei nodi successivi (terza istruzione: q = q->pun ); la ripetizione for continua se non si è arrivati in fondo (q!= 0 AND < N). Applicando la legge di DeMorgan il for si arresta se si è arrivati in fondo (q = = 0 OR >= N). In questo caso, va eseguito l inserimento del nuovo nodo. Alle righe 8, 9 e 10 viene creato un nuovo nodo e in esso vengono inseriti i nuovi dati. Dalla riga 12 alla riga 15 vengono aggiornati i atori: della testa se il nuovo dato va inserito per primo o del nodo prima del quale va inserito il nuovo intero. Prova di esecuzione 16