Sei sulla pagina 1di 40

Programmazione C

Strutture dati dinamiche liste

@ Giuseppina Gini 2008/9

Modificare le dimensioni
array e struct sono caratterizzati da operazioni che permettono un accesso diretto alle singole componenti ma non consentono di modificare la dimensione della struttura. definiamo invece strutture nelle quali possibile
modificare le dimensioni aggiungendo o togliendo elementi, ma laccesso alle componenti non sempre il risultato di una sola operazione ma pu richiedere lesecuzione di un numero di passi proporzionale alla dimensione della struttura stessa.

@ Giuseppina Gini 2008/9

LISTE
Una lista e una struttura dati ricorsiva che consente di accorpare elementi della stessa tipologia mantenendoli in ordine logico (non fisico) Dato un insieme di valori U, chiamiamo lista una sequenza finita L di elementi di U. L pu essere la lista vuota, denotata con il simbolo ; altrimenti L una sequenza finita della forma
L = (a1, a2, . . . , an), dove n >= 1 e ai U per ogni i = 1, 2, . . . , n.

<lista>::= |<elemento><lista> Il tipo di dato astratto lista definito da: notazione insieme di primitive
@ Giuseppina Gini 2008/9

OPERAZIONI PRIMITIVE SU LISTA


1. costruttore di lista 2. lista_vuota? NULL? (lista). 3.prendi_primo_elemento della lista: si puo fare se la lista non e vuota, e restituisce un elemento. PRIMO_EL (lista) 4. prendi_resto della lista tolto il primo elemento: restituisce una lista accorciata. RESTO (lista) 5. attacca_elemento_in_testa ad una lista. CONS (e, lista) aggiunge e all'inizio di lista. NULL?() -> vero PRIMO_EL (e1, e2, e3) -> e1 RESTO (e1, e2, e3) -> (e2, e3) CONS (e0, lista) -> (e0, e1, e2, e3)
@ Giuseppina Gini 2008/9

Esempio 1: restituisci elemento di posto n


definire la funzione nth che prende come argomenti un intero n ed una lista e ritorna l'ennesimo elemento della lista (numerata a partire da 0). - se n=0, restituisce primo_el - altrimenti ritorna l'(n-1) elemento del resto della lista. nth (n x) = se n=0 allora return PRIMO_EL (x) altrimenti return (nth (n-1, RESTO (x)) nth( 2 (0 1 2 3 4)) = > nth(1 (1 2 3 4))=> nth(0 (2 3 4)) RETURN 2
@ Giuseppina Gini 2008/9

Esempio 2: restituisci la lunghezza della lista


lunghezza (x) = se NULL? (x) allora return 0 altrimenti return lunghezza (RESTO( x)) + 1

lunghezza(0 1 2) lunghezza(1 2) + 1 lunghezza(2)+1 +1 lunghezza() +1+1 +1 return 0 return 1 return 2 return 3


@ Giuseppina Gini 2008/9

Esempio 3: inserimento in ordine


In una lista ordinata il nuovo elemento viene inserito nella lista quando si e raggiunta la posizione voluta. Se lelemento minore del primo della lista, va messo in testa insert-crescente( x y) = se NULL? (y) allora return (list x) altrimenti se x < PRIMO_EL( y) allora return CONS( x y) altrimenti return CONS (PRIMO_EL( y), insert-crescente (x, RESTO (y)))

@ Giuseppina Gini 2008/9

RAPPRESENTAZIONI GRAFICHE
E opportuno vedere la lista come composta da scatole doppie, che contengono per ogni elemento lelemento stesso ed un modo per raggiungere lelemento successivo (puntatore). la lista e caratterizzata da un puntatore daccesso la lista pu essere scandita solo dallinizio alla fine; la fine contrassegnata da un puntatore finale nullo. In genere i linguaggi imperativi non hanno la lista come struttura dati direttamente disponibile, e possono implementare la lista in diversi modi: 1. Rappresentazione mediante arrays 2. Rappresentazione mediante puntatori.
@ Giuseppina Gini 2008/9

Rappresentazione grafica
Lista di tre elementi

E1 P1

E2 P2

E3

NULL

@ Giuseppina Gini 2008/9

Liste in array
La rappresentazione mediante array richiede array di record il primo campo e lelemento il secondo e lindice in cui trovare il prossimo elemento. es: rappresentiamo in un array di 10 righe e 2 colonne la lista (e1, e2, e3); puntatore daccesso = 1 typedef struct{ int pos; int info;}ElemLista; ElemLista MIA_lista [10];
9
@ Giuseppina Gini 2008/9

0 1 2 3 4 5 6 7 8

e3 e1 * * * e2 * * * *

-1 5 * * * 0 * * * *

Array e lista libera


0 1 2 3 4 5 6 7 8 9 e3 e1 * * * e2 * * * * -1 5 6 2 7 0 4 8 9 -1

per poter inserire elementi e opportuno che le posizioni non usate siano collegate a lista, (lista libera). Nella stessa array allora convivono due liste, la lista delle informazioni e la lista libera. In questo caso il puntatore lista libera = 3

@ Giuseppina Gini 2008/9

Gestione dinamica della memoria


Per non allocare tutta la memoria si usano strutture dinamiche
Si alloca memoria solo quando occorre inserire dati Si libera memoria quando il dato non serve pi

Per gestire la memoria, occorre introdurre alcune nuove funzioni che fanno riferimento ai puntatori

@ Giuseppina Gini 2008/9

Allocare memoria dinamicamente


le variabili dinamiche (di ogni tipo)
Si allocano o deallocano durante lesecuzione del programma Sono anonime (si accede mediante puntatori, non hanno un nome)

Occorrono le funzioni della <stdlib.h>


malloc per allocazione prende da heap (zona di memoria libera mantenuta dal SO) free per rilascio di memoria (torna in heap)

@ Giuseppina Gini 2008/9

heap

@ Giuseppina Gini 2008/9

La funzione sizeof
sizeof
Ritorna la grandezza in bytes delloperando Per arrays ritorna (size di 1 elemento * numero elementi) sizeof(int) 4 bytes
int myArray[ 10 ]; printf( "%d", sizeof( myArray ) );

stampa 40

sizeof si usa con


Nomi di variabili Nomi di tipo costanti
@ Giuseppina Gini 2008/9

malloc e free
TipoDato *punt; punt = malloc (sizeof(TipoDato)); Dichiara punt come puntatore a TipoDato Crea in memoria la variabile del tipo TipoDato Restituisce lindirizzo della variabile creata Assegna questo indirizzo a punt, che ora punta alla variabile dinamica free(punt); Rilascia lo spazio puntato da punt per tanti bytes quanto indicato da TipoDato
@ Giuseppina Gini 2008/9

Puntatori per la lista


Si definisce Lista, il puntatore alla lista la memoria viene allocata solo quando ce da inserire un elemento

Lista

E1

P1

E2

P2

E3

NULL

@ Giuseppina Gini 2008/9

Dichiarazione di elemento
ELEMENTO: Per ogni scatola doppia usiamo una struct, con un primo campo che contiene lelemento ed un secondo campo che e un puntatore al tipo che si sta definendo.
struct EL {dataType Info; struct EL *Prox}; typedef struct EL ElemLista;

@ Giuseppina Gini 2008/9

Dichiarazione di lista di TipoDato


typedef struct EL { TipoDato Info; struct EL *Prox; } ElemLista; typedef ElemLista *ListaDiElem; ListaDiElem Lista;
struct EL definisce i campi di ogni elemento typedef rinomina il tipo structEL come ElemLista typedef definisce il nuovo tipo ListadiElem come puntatore al tipo ElemLista Lista perci il puntatore alla lista

@ Giuseppina Gini 2008/9

Funzioni di base - 1
Inizializzazione
con variable globale Lista = NULL; con procedura su variabile globale void Inizializza (void) { Lista = NULL;}

@ Giuseppina Gini 2008/9

Funzioni di base - 2
Lista vuota? int ListaVuota (ListadiElem Lista) /* Lista, passata per valore, punta al primo elemento*/ { if (Lista == NULL) return 1; else return 0; } sarebbe meglio definire il tipo boolean (vedi poi) Esempio di chiamata: int vuota; vuota = ListaVuota (Lista);
@ Giuseppina Gini 2008/9

Tipo boolean per enumerazione


enum boolean { false, true};

gli identificatori false e true hanno valori 0 e 1

@ Giuseppina Gini 2008/9

Funzioni di base - 3
Prendi il primo elemento di una lista - di tipo int
int PrimoElem (ListadiElem Lista) { if (ListaVuota(Lista)== false) return Lista->Info else return error;}

Lista->Info scrittura abbreviata per accedere al campo Info della variabile dereferenziata *Lista Lista->Info uguale a *Lista.Info
(ListaVuota(Lista)== false) come

(Lista != NULL)
@ Giuseppina Gini 2008/9

Funzioni di base - 4
Prendi il resto della lista tolto il primo elemento
ListaDiElem RestoLista (ListadiElem Lista) { if(Lista != NULL) /*ci sono elementi*/ return Lista->Prox else return error;}

Lista->Prox scrittura abbreviata per accedere al campo Prox della variabile dereferenziata *Lista equivalente a *Lista.Prox

@ Giuseppina Gini 2008/9

Esempio: ricerca elemento


Scandire la lista di interi fino a trovare o l'elemento o la fine lista restituisce vero o falso boolean Ricerca (ListadiElem Lista, int Cercare) {while (Lista != NULL)/*non vuota*/ {if (Lista->Info == Cercare) return true; Lista = Lista->Prox;}}/*by value*/ return false;}

@ Giuseppina Gini 2008/9

-> ricerca ricorsiva


Se Lista vuota return false altrimenti return ricerca (resto Lista) boolean Ricerca (ListadiElem Lista, int Cercare) { if (Lista == NULL) return false; if (Lista->Info == Cercare) return true; else return Ricerca (Lista-> Prox, Cercare); }
@ Giuseppina Gini 2008/9

Funzioni di base 5
Inserire in testa

Lista

punt

elem

Alloco una scatola per mettere elem A Prox assegno Lista A Lista assegno punct
@ Giuseppina Gini 2008/9

Inserimento in testa (come funzione, passaggio per valore)


ListaDiElem InserisciTesta (ListadiElem Lista, int Elem) { ElemLista * punt; punt = malloc (sizeof(ElemLista)); punt->Info = Elem; punt->Prox = Lista; return punt; } chiamata: Lista = InserisciTesta (Lista, new);
@ Giuseppina Gini 2008/9

inserimento
Inserimento in testa (come procedura, passaggio per indirizzo) void InserisciTesta (ListadiElem *Lista, int Elem) { ElemLista *punt; punt = malloc (sizeof(ElemLista)); punt->Info = Elem; punt->Prox = *Lista; *Lista = punt; } *Lista indirizzo primo elemento della lista
@ Giuseppina Gini 2008/9

Inserimento in coda (ricorsivo)


ListaDiElem InserisciCoda(ListadiElem Lista, int Elem) { ElemLista *punt; if (ListaVuota(Lista)) {punt = malloc (sizeof(ElemLista)); return punt->Info = Elem; InserisciTesta(ListadiElem punt->prox = NULL; lista, int Elem); return punt;} else {Lista->Prox=InserisciCoda(Lista>Prox, Elem); return Lista;}}/*il puntatore a lista*/ chiamata: Lista = InserisciCoda (Lista, Nuovo);
@ Giuseppina Gini 2008/9

Inserimento in ordine
ListaDiElem InserisciOrdine(ListadiElem Lista, int Elem) { Elemlista *punt, *puntcorr, *puntprec; puntprec = NULL; puntcorr = Lista; while (puntcorr !=NULL&&Elem>puntcorr->Info) /*va avanti*/ {puntprec = puntcorr; puntcorr = puntcorr->Prox;} /*ci siamo*/ punt = malloc (sizeof(ElemLista)); punt->Info = Elem; punt->Prox = puntcorr; if (puntprec != NULL) /* siamo all' interno*/ {puntprec->Prox= punt; return Lista; } else return punt;} /* in testa*/ chiamata Lista = InserisciOrdine (Lista,new);
@ Giuseppina Gini 2008/9

Cancellazione di elemento (ricorsiva)


ListaDiElem Cancella (ListadiElem Lista, int Togli) {ElemLista *puntemp; if (ListaVuota(Lista)== false)/*ci sono ei*/ {if(Lista->Info == Togli)/* trovato*/ {puntemp = Lista->Prox; free (Lista); return puntemp; } else {Lista->Prox = Cancella(Lista->Prox, Togli); return Lista; }} else return Lista ;*/ vuota*/} chiamata : Lista = Cancella(Lista, Elem);
@ Giuseppina Gini 2008/9

#include <stdio.h> #include <stdlib.h> struct listNode { char data; struct listNode *nextPtr; }; typedef struct listNode ListNode; typedef ListNode *ListNodePtr; /*tipo dato lista*/ void insert( ListNodePtr *, char ); /*prototipi*/ char delete( ListNodePtr *, char ); int isEmpty( ListNodePtr ); void printList( ListNodePtr ); void instructions( void ); main() { ListNodePtr startPtr = NULL; int choice; char item; instructions();
@ Giuseppina Gini 2008/9

Liste di char: programma completo con menu Usa chiamate per reference

/* mostra il menu */

printf( "? " ); scanf( "%d", &choice );

while ( choice != 3 ) { switch ( choice ) { case 1: printf( "Enter a character: " ); scanf( "\n%c", &item ); insert( &startPtr, item ); printList( startPtr ); break; case 2: if ( !isEmpty( startPtr ) ) { printf( "Enter character to be deleted: " ); scanf( "\n%c", &item ); if ( delete( &startPtr, item ) ) { printf( "%c deleted.\n", item ); printList( startPtr ); } else printf( "%c not found.\n\n", item ); } else printf( "List is empty.\n\n" ); break; default: printf( "Invalid choice.\n\n" ); instructions(); break; }

@ Giuseppina Gini 2008/9

printf( "? " ); scanf( "%d", &choice ); } printf( "End of run.\n" ); return 0; } /* stampa il menu */ void instructions( void ) { printf( "Enter your choice:\n" " 1 to insert an element into the list.\n" " 2 to delete an element from the list.\n" " 3 to end.\n" ); } /* inserisci in ordine un valore nella lista */ void insert( ListNodePtr *sPtr, char value ) { ListNodePtr newPtr, previousPtr, currentPtr; newPtr = malloc( sizeof( ListNode ) ); if ( newPtr != NULL ) { newPtr->data = value; newPtr->nextPtr = NULL;
@ Giuseppina Gini 2008/9

previousPtr = NULL; currentPtr = *sPtr;

while ( currentPtr != NULL && value > currentPtr->data ) { previousPtr = currentPtr; currentPtr = currentPtr->nextPtr; } if ( previousPtr == NULL ) { newPtr->nextPtr = *sPtr; *sPtr = newPtr; } else { previousPtr->nextPtr = newPtr; newPtr->nextPtr = currentPtr; } } else printf( "%c not inserted. No memory available.\n", value ); } /* cancella un elemento */ char delete( ListNodePtr *sPtr, char value ) { ListNodePtr previousPtr, currentPtr, tempPtr; if ( value == ( *sPtr )->data ) { tempPtr = *sPtr; *sPtr = ( *sPtr )->nextPtr; /* stacca il nodo */ free( tempPtr ); /* cancella */
@ Giuseppina Gini 2008/9

return value; }

else { previousPtr = *sPtr; currentPtr = ( *sPtr )->nextPtr; while ( currentPtr != NULL && currentPtr->data != value ) { previousPtr = currentPtr; currentPtr = currentPtr->nextPtr; } if ( currentPtr != NULL ) { tempPtr = currentPtr; previousPtr->nextPtr = currentPtr->nextPtr; free( tempPtr ); return value; } }

} /* lista vuota?*/ int isEmpty( ListNodePtr sPtr ) { return sPtr == NULL; } /* stampa la lista */ void printList( ListNodePtr currentPtr ) { if ( currentPtr == NULL )

@ Giuseppina Gini 2008/9

printf( "List is empty.\n\n" ); else { printf( "The list is:\n" ); while ( currentPtr != NULL ) { printf( "%c --> ", currentPtr->data ); currentPtr = currentPtr->nextPtr; } printf( "NULL\n\n" ); } } Enter your choice: 1 to insert an element into 2 to delete an element from 3 to end. ? 1 Enter a character: B The list is: B --> NULL ? 1 Enter a character: A The list is: A --> B --> NULL ? 1 Enter a character: C The list is: A --> B --> C --> NULL ? 2 Enter character to be deleted: D not found. ? 2 Enter character to be deleted: B deleted. The list is: A --> C --> NULL the list. the list.

@ Giuseppina Gini 2008/9

esercizio
Si scriva una funzione C ricorsiva che data una lista l restituisce 1 se la lista ordinata, 0 altrimenti. La lista vuota si ritiene ordinata, cos come la lista contenente un solo elemento. Si consideri ad esempio la seguente lista: La procedura restituir il valore 1, poich ogni elemento contiene un valore maggiore dellelemento precedente.

12

15

27

99

@ Giuseppina Gini 2008/9

Soluzione:
int list_is_ordered(ListaDiElem l) { if (l == NULL) return 1; if (l->prox == NULL) return 1; return list_is_ordered(l->prox)&& (l->info < l->prox>info); }

@ Giuseppina Gini 2008/9