struttura di una lista legata una lista legata è una variabile strutturata in cui ogni elemento...

29

Upload: luigi-pucci

Post on 02-May-2015

225 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento
Page 2: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Struttura di una lista legata

Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento successivo. Ogni elemento della struttura viene detto nodo. Tutti i nodi della struttura sono implementati come variabili dinamiche.

La figura seguente è un esempio di rappresentazione grafica di una lista.

p4 è il puntatore nullo: non punta a niente

Pkgiallo p1 bleu p2 rosso p3 nero p4

Page 3: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

In questo esempio Pk è il puntatore alla lista, ogni nodo della lista è composto da un dato e da un puntatore al nodo successivo: (giallo, p1) (bleu, p2) (rosso, p3) (nero, p4). La stessa situazione può essere descritta con la tabella seguente:

INDIRIZZOTIPO CONTENUTO OSSERVAZIONI

0x0064fdf0 Nodo giallo p1= 0x0064fe0f p1 = indirizzo prossimo nodo

0x0064fe0f Nodo bleu p2= 0x0064fe07 p2= indirizzo prossimo nodo

0x0064fe07 Nodo rosso p3= 0x0064fff0 p3=indirizzo prossimo nodo

0x0064fff0 Nodo Nero P4=0 o NULL p4= fine della lista

p4 è il puntatore nullo: non punta a niente

Pkgiallo p1 bleu p2 rosso p3 nero p4

Page 4: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Una lista lineare legata è una collezione di oggetti (gli elementi della lista o nodi) definiti dinamicamente, uniti insieme da puntatori. Ogni singola variabile puntatore è costituita da almeno due campi: il primo contiene l’informazione, il secondo l’indirizzo dell’elemento successivo.

Nodo: è una variabile dinamica che costituisce l’elemento della lista legata.

Pkgiallo p1 bleu p2 rosso p3 nero p4

Page 5: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Dalla definizione emerge chiaramente che per gestire una lista è sufficiente conoscere il puntatore al suo primo elemento.

Il nodo è una variabile strutturata di tipo struct in cui uno dei campi è formato da un puntatore al prossimo nodo: chiameremo campo next tale campo, mentre gli altri dati della struct li indicheremo come campo dati (esso conterrà le informazioni specifiche).

In questo modo tutti i nodi sono collegati insieme per formare il dato strutturato denominato lista.

Pkgiallo p1 bleu p2 rosso p3 nero p4

Page 6: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Supponiamo di voler costruire la lista sottostante; per implementarla in C++ definiamo il tipo Tnodo:

.

struct Tnodo { char nome[10]; Tnodo* next; }

Pkgiallo p1 bleu p2 rosso p3 nero p4

Page 7: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Una tipica lista inizia con una variabile puntatore al nodo e termina con il puntatore nullo. Nell’esempio in figura Pk punta al primo nodo posto all’inizio della lista; per accedere a tale nodo basta dereferenziare pk .

(*pk).nome contiene il nome di 10 caratteri della struttura Tnodo

(*pk).next contiene l’indirizzo del nodo successivo. struct Tnodo { char nome[10]; Tnodo* next; }

La struttura Tnodo, in questo esempio, è costituita da un array di 10 caratteri e da un puntatore next al prossimo nodo; è opportuno notare come il puntatore punta ad un tipo che viene definito in quello stesso momento.

anna p1 ugo p2 ciro p3 dario p4Pk

Page 8: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

In luogo della scrittura precedente si utilizza la seguente in cui non appare il simbolo * di derenfereziazione:

pk->nomepk->next

Il simbolo -> viene detto operatore freccia: esso si applica al puntatore della struttura e non alla variabile che denota la struttura.

Page 9: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Implementazione di una lista legata

Una lista può essere paragonata ad un insieme, i cui elementi sono i nodi della lista (o, meglio, il campo informazione del nodo). Le prime operazioni da introdurre in un insieme sono: inserimento, cancellazione, ricerca.

Come primo passo introduciamo un semplice esempio di nodo a cui fare riferimento. A questo scopo, per semplificare, riteniamo opportuno prendere come informazione base del nodo un numero intero; avremo quindi

struct Tnodo { int info; Tnodo *next;};typedef Tnodo* Pnodo;

Page 10: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Con typedef Tnodo* Pnodo abbiamo definito un nuovo tipo, Pnodo, che rappresenta un puntatore a Tnodo.

Il nodo della lista legata lineare è costituito da un campo info, in questo caso un intero, e da un campo next che contiene un puntatore alla struttura Tnodo. Vogliamo creare un nodo nella memoria heap con queste caratteristiche.

Temp è di tipo PNodoinfo è un interonext è di tipo PNodoNULL non punta a niente

Temp

NULL

info nextstruct Tnodo { int info; Tnodo *next;};typedef Tnodo* Pnodo;

Page 11: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Scriviamo una procedura CreaNodo che ha in input l’informazione info e che restituisce il puntatore Temp del nodo creato:

Se la lista è vuota inseriamo il nodo appena creato come primo elemento; per ottenere tale risultato poniamo L = Temp, dove L è ovviamente di tipo Pnodo.

void CreaNodo(int info1, Pnodo& Temp) { Temp= new Tnodo; Temp->info=info1; Temp->next=NULL;}

8 next

LTemp

NULL

Pnodo L,Temp;L=NULL;int info1;……………………info1=8;CreaNodo(info1, Temp)if (L==NULL) L=Temp;

Page 12: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Se la lista non è vuota, ma contiene già qualche elemento, possiamo decidere se inserire il nuovo nodo in testa o in coda.

Volendo inserire il nuovo nodo in testa, cioè all’inizio della lista, potremmo porre ancora L =Temp; in questo caso, però, perderemmo il contenuto di L.

I passi da fare sono allora: conservare il valore di L in Temp->next e successivamente porre L=Temp

Page 13: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

8

L

Temp

NULL

3 11

Temp

NULL 6

Pnodo Insert (int info1, Pnodo L) {//E’una funzione che inserisce l'elemento in testa alla lista Pnodo Temp; CreaNodo(info1, Temp); Temp->next=L; return Temp;}

Lista di partenza

Nuovo nodo

8

NULL

3 11 6

L

LNuova lista

Page 14: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Scriviamo ora una procedura che, assegnato un nodo con puntatore Temp ed una lista L, inserisce il nodo Temp in coda alla lista L.

Osserviamo che se la lista è vuota allora è sufficiente creare il nodo con puntatore L; se la lista non è vuota dobbiamo scorrerla tutta fin quando il puntatore corrente raggiunge NULL.

Attenzione che nel momento in cui viene raggiunta la fine della lista si perde il legame con la lista stessa in quanto non si conosce il puntatore al nodo precedente.

Page 15: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

La freccia verso il basso rappresenta un puntatore a NULL; se conserviamo il puntatore precedente (PREC) ed il valore del puntatore corrente (CURR) è NULL, allora per mantenere la lista linkata dobbiamo porre: PREC->next=Temp

PREC

8

L

Temp

NULL

3 11

NULL 6

Lista di partenza

Nuovo nodo

8

CURR

3 11

L

NULL 6

Nuova lista

Page 16: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

La procedura che inserisce un nodo in coda ha la seguente intestazione

void InsertCoda(int info1,Pnodo &L );

con la seguente descrizione

if L==NULL Creanodo(info1,L)else scorri tutta la lista finché non raggiungi la fine, conservando sia il nodo precedente (PREC) che quello corrente (CURR);quando hai raggiunto la fine esegui

CreaNodo(info1,PREC->next)

Page 17: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

La parte evidenziata in corsivo rappresenta un ciclo che ha questa struttura:

inizializzazione: curr=L e prec=NULL;condizione del ciclo: while (curr != NULL)corpo del ciclo: prec=curr e curr=curr->next

In definitiva si ha void InsertCoda(int info1,Pnodo &L)

{Pnodo prec, curr; if (L==NULL) CreaNodo(info1, L); else { curr=L; prec=NULL; while (curr!=NULL) { prec=curr; curr=curr->next; } CreaNodo(info1, prec->next); }}

Page 18: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Introduciamo ora la funzione Insert che permette di aggiungere un elemento all’interno della lista dopo un preassegnato nodo individuato dal suo puntatore. Supponiamo di dover inserire il nodo nella lista L dopo il nodo avente come puntatore P. tra gli elementi 8 ed 3, e che il puntatore del nodo con item 8 è L. A questo scopo basta porre

Temp->next = P->next e P->next = Temp

Pnodo Insert (int info1, Pnodo P, Pnodo &L) {/*Inserisce l'elemento all’interno della lista dopo il nodo puntato da P */ Pnodo Temp; CreaNodo(info1, Temp); Temp->next=P->next; P->next=Temp; return L;}

Page 19: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Pnodo Insert (int info1, Pnodo P, Pnodo &L) {/*Inserisce l'elemento all’interno della lista dopo il nodo puntato da P */ Pnodo Temp; CreaNodo(info1, Temp); Temp->next=P->next; P->next=Temp; return L;}

8

L

Temp

NULL 3 next 11

NULL 6 next

Lista di partenza

Nuovo nodo

8 3 next 6

L

NULL 11

Nuova lista

P

Page 20: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Scriviamo ora una funzione inserisciNodoMezzo nel caso in cui si deve aggiungere un elemento all’interno della lista dopo una determinata chiave.

Dovremo prima cercare la chiave se esiste, e quindi inserire il nodo come prima.

Page 21: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

void inserisciNodoMezzo( int info1,Pnodo &L) {// inserisce un nuovo nodo in mezzo alla listaint inf;Pnodo prec, curr, Temp;cout<<"Dammi valore nodo ";cin>>inf;cout<<endl; if (L==NULL) creaNodo(info1, L); // caso lista vuota else { curr=L; prec=NULL; while ((curr->info!=info1)&&(curr->next!=NULL) { prec=curr; // cerco la chiave curr=curr->next; } if (curr->next!=NULL) // chiave trovata nel mezzo { creaNodo(inf, Temp); Temp->next=curr->next; curr->next=Temp; } if ((curr->info==info1)&&(curr->next==NULL)) { creaNodo(inf, Temp); // chiave trovata alla fine curr->next=Temp; }

}}

Utilizziamo due puntatori:

curr e prec che individuano il

puntatore di scorrimento

della lista L (curr) e il

puntatore dell’elemento

immediatamente precedente

(prec).

Se e quando curr->info è

uguale all’info dopo del quale

vogliamo porre il nuovo

nodo, allora operiamo come

nel caso di inserimento noto

il puntatore che ora sarà curr.

Page 22: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Analizziamo ora la cancellazione di un nodo da una lista L.

Per poter cancellare un nodo contenente un dato valore dobbiamo:

• cercare il nodo all’interno della lista• cancellare il nodo con delete mantenendo il legame dentro la lista.

La procedura CancellaNodo, scritta in modo ricorsivo, ha la seguente struttura

void CancellaNodo(Pnodo &L, int info1)if (L!=NULL) if (L->info=info1) cancella mantenendo il legame nella lista else richiama la funzione col nodo successivo

Page 23: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Per poter eseguire il punto 2 è necessario

• conservare il puntatore L in un’altra variabile Temp• porre L=L->next• cancellare la memoria a cui punta TempTenendo presente queste osservazioni possiamo scrivere la procedura

CancellaNodo come segue. void CancellaNodo(Pnodo &L, int info1) { Pnodo Temp; if (L!=NULL) { if (L->item==info1) { Temp=L; L=L->next; delete Temp; } else CancellaNodo(L->next, info1); }}

Page 24: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

// PROTOTIPIvoid costruisciLista(Pnodo &);void stampaLista(Pnodo );void creaNodo (int, Pnodo&); Pnodo inserisciNodoTesta (int,Pnodo );void inserisciNodoCoda (int,Pnodo &); void inserisciNodoMezzo (int,Pnodo &); void cancellaNodo (int,Pnodo &);

void costruisciLista(Pnodo &L){Pnodo nodo; int item; string NomeIn, NomeOut; ifstream filista; ofstream outlista; NomeIn="L5.txt"; filista.open(NomeIn.c_str()); if (!filista) { cerr<<"Non si puo' aprire il file"<<endl; system("pause"); } filista>>item; creaNodo(item,L); while (!filista.eof()) { filista>>item; inserisciNodoCoda(item,L); } }

void stampaLista(Pnodo L){ while (L!=NULL){ cout<<" "<<L->info; L=L->next;} }

Pnodo inserisciNodoTesta ( int info1,Pnodo L)

{// inserisce un nuovo nodo in testa alla listaPnodo Temp; creaNodo(info1, Temp); Temp->next=L; return Temp; }

Page 25: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

void inserisciNodoCoda ( int info1,Pnodo &L) {// inserisce un nuovo nodo in coda alla listaPnodo prec, curr; if (L==NULL) creaNodo(info1, L); else { curr=L; prec=NULL; while (curr!=NULL) { prec=curr; curr=curr->next; } creaNodo(info1, prec->next); }}

Page 26: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

void inserisciNodoMezzo( int info1,Pnodo &L) {// inserisce un nuovo nodo in mezzo alla listaint inf;Pnodo prec, curr, Temp;cout<<"Dammi valore nodo ";cin>>inf;cout<<endl; if (L==NULL) creaNodo(info1, L); else { curr=L; prec=NULL; while ((curr->info!=info1)&&(curr->next!=NULL)) {prec=curr; curr=curr->next; } if (curr->next!=NULL) { creaNodo(inf, Temp); Temp->next=curr->next; curr->next=Temp; } if ((curr->info==info1)&&(curr->next==NULL)) { creaNodo(inf, Temp); curr->next=Temp; } }}

Page 27: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento
Page 28: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Una procedura iterativa è invece la seguente void CancellaNodo(Pnodo &L, int info1) { Pnodo prec=NULL; if ((L->next!=NULL)&(L->info!=info1))

{prec=L; L=L->next;}

if (L->next!=NULL){ prec->next=L->next; delete L; } else cout<<“ nodo non trovato “<<endl; }}

Page 29: Struttura di una lista legata Una lista legata è una variabile strutturata in cui ogni elemento mantiene l’indirizzo (mediante un puntatore) dell’elemento

Nell’allegato liste.cpp è riportato un codice per il trattamento

delle liste legate con le seguenti funzioni:

void costruisciLista(Pnodo &); //costruisce una lista a partire da un file testo

void stampaLista(Pnodo ); //stampa una lista

void creaNodo (int, Pnodo&); //crea un nodo

Pnodo inserisciNodoTesta (int,Pnodo &); // inserisci un nodo in testa

void inserisciNodoCoda (int,Pnodo &); // inserisci un nodo in coda Pnodo

void inserisciNodoMezzo (int,Pnodo &); // inserisci un nodo nel mezzo

void cancellaNodo (int,Pnodo &); // cancella un nodo

void cercaItem(int ,Pnodo ,Pnodo &); // cerca un nodo con una data info

bool listaVuota(Pnodo); // verifica se una lista è vuota

int cercaPosizione(int, Pnodo); // cerca la posizione lungo la lista di un dato nodo

int contaNodi(Pnodo); // conta quanti nodi ha la lista