Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Liste
Indice
1
Tipi di Dato Astratto
Abstract Data Type (ADT)
Liste(1)
• Quando dobbiamo scandire una collezione di
oggetti in modo sequenziale e non sequenziale,
un modo conveniente per rappresentarli è quello
di organizzare gli oggetti in un array.
• Esempi:
(1, 2, -3, 5, -10) è una sequenza di interi.
(‘a’, ‘d’, ‘1’, ‘F’) è una sequenza di caratteri.
2
Liste(1)
• Una soluzione alternativa all’uso di array per
rappresentare le liste quando l’accesso non sequenziale
non è un requisito, consiste nell’uso delle cosiddette liste
(concatenate).
• In una lista concatenata i vari elementi che
compongono la sequenza di dati sono rappresentati in
zone di memoria che possono anche essere distanti fra
loro (al contrario degli array, in cui gli elementi sono
consecutivi).
• In una lista concatenata, ogni elemento contiene
informazioni necessarie per accedere all’elemento
successivo.
Liste
• Vantaggi rispetto all’array:
Flessibilità
di modifica
Riduzione e aumento dinamico della dimensione .
Memorizzo solo quello che mi serve. Mentre con array potrei
sprecare memoria (array sovradimensionato).
• Svantaggi rispetto all’array:
Lo
svantaggio principale consiste nell’onerosità nell’accesso ai
suoi elementi.
• Unico modo per raggiungere un dato elemento consiste nello
scorrere la lista dal nodo iniziale.
3
Liste
• Modello matematico
Una lista L e’ una sequenza di zero o più elementi di un tipo
di dato ( TipoElemento )
a1,a2,…an
Il numero di elementi n di tale lista è detta lunghezza.
Se n ≥ 1, a1 è il primo elemento
Se n =0, la lista è vuota
Ordine lineare secondo posizione nella lista:
• a1 precede a2
• a4 segue a3
Utile definire esistenza di FINE(L)
La distanza tra primo elemento lista e FINE(L)
varierà nel tempo
Lista dinamica
Implementazione
Elemento
Puntatore
1 della
a elemento
lista 2 Puntatore NULL
Ultimo
Lista elemento
e1 e2 en
Puntatore alla
“testa di lista”“testa di lista” “coda di lista”
4
Dichiarazione lista dinamica (1)
• Dichiarazioni abbreviate:
ElemLista *Lista1;
struct EL *Lista1
5
Liste - Operazioni
• Inserisci elemento a nella lista L
Testa, Coda, Lista Ordinata,
• Ricerca elemento a nella lista L
• Cancella elemento a dalla lista L
• Estrai
testadella lista L
coda della lista L
successore di elemento nella lista L
predecessore di elemento nella lista L
Lista
6
Inizializzazione (3) senza parametro
#include <stdlib.h>
ListaDiElem Lista1;
void Inizializza(void)
{
Lista1 = NULL;
}
Inizializzazione (2)
#include <stdlib.h>
7
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)
if (Lista != NULL)
{
Cursore = Lista; /* La lista non è vuota */
while (Cursore != NULL)
{
if (Cursore–>Info == ElemCercato) return true;
Cursore = Cursore–>Prox;
8
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;
if (Lista != NULL)
{
Cursore = Lista; /* La lista non è vuota */
while (Cursore != NULL)
{
if (Cursore–>Info == ElemCercato) return true;
Cursore = Cursore–>Prox;
9
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;
10
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);
}
return false;
Base
else
if (Lista–>Info == ElemCercato)
return true;
else
return Ricerca(Lista–>Prox, ElemCercato);
}
11
Ricerca di un elemento nella lista,
versione ricorsiva
boolean Ricerca (ListaDiElem Lista,
TipoElemento ElemCercato)
{
if (Lista == NULL)
Soluzioni
return false;
Base
else
if (Lista–>Info == ElemCercato)
return true;
else
return Ricerca(Lista–>Prox, ElemCercato);
}
return false;
Base
else
if (Lista–>Info == ElemCercato)
return true;
else
return Ricerca(Lista–>Prox, ElemCercato);
}
12
Accesso testa e 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 all'elemento che segue elemento di
testa. Essa non deve modificare il parametro originario. Anche questa
assume l'ipotesi che il parametro passatole sia una lista non vuota */
CodaLista
Ultimo
Lista elemento
e1 e2 en
Punt
Punt = malloc(sizeof(ElemLista));
Punt–>Info = Elem;
Punt
Elem
Lista
e1 e2 … en
13
Inserimento nuovo elemento in testa (2)
Elem
Lista
e1 e2 en
e1 e2 en
Lista1
14
Inserimento nuovo elemento in testa (3)
e1 e2 en
Lista1
e1 e2 en
Lista1
15
Inserimento nuovo elemento in testa (3)
e1 e2 en
Lista1
16
Lista*1 Lista*2 Lista*3 Lista*n Lista*n+1 Cont.
e1 e2 en-1 en
Lista1
e1 e2 en-1 en
Lista1
Punt
Lista*1 Lista*2 Lista*3 Lista*n+1
Elem
e1 e2 en-1 en
Lista1
if (ListaVuota (*Lista))
{
Punt = malloc(sizeof(ElemLista));
Punt–>Prox = NULL;
Punt–>Info = Elem;
*Lista = Punt;
}
else InserisciIncoda (&((*Lista)–>Prox), Elem);
}
17
Inserimento nuovo elemento in coda (2)
Ricorsiva
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);
}
if (ListaVuota (*Lista))
{
Punt = malloc(sizeof(ElemLista));
Punt–>Prox = NULL;
Punt–>Info = Elem;
*Lista = Punt;
}
else InserisciIncoda (&((*Lista)–>Prox), Elem);
}
18
Inserimento nuovo elemento in coda (3)
Ricorsiva
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);
}
19
Cont.
39
20
Inserimento nuovo elemento in
lista ordinata
void InserisciInOrdine (ListaDiElem *Lista,
TipoElemento Elem);
{
ElemLista *Punt, *PuntCorrente, *PuntPrecedente;
PuntPrecedente=NULL;
PuntCorrente=*Lista;
while ((PuntCorrente != NULL) && (Elem > PuntCorrente->Info)
{
PuntPrecedente = PuntCorrente;
PuntCorrente = PuntCorrente->Prox;
}
Punt = malloc(sizeof(ElemLista));
Punt–>Prox = PuntCorrente;
Punt–>Info = Elem;
if(PuntPrecedente != NULL) PuntPrecedente->Prox=Punt;
` else *Lista=Punt;
}
21
Inserimento nuovo elemento in
lista ordinata
void InserisciInOrdine (ListaDiElem *Lista,
TipoElemento Elem);
{
ElemLista *Punt, *PuntCorrente, *PuntPrecedente;
PuntPrecedente=NULL;
PuntCorrente=*Lista;
while ((PuntCorrente != NULL) && (Elem > PuntCorrente->Info)
{
PuntPrecedente = PuntCorrente;
PuntCorrente = PuntCorrente->Prox;
}
Punt = malloc(sizeof(ElemLista));
Punt–>Prox = PuntCorrente;
Punt–>Info = Elem;
if(PuntPrecedente != NULL) PuntPrecedente->Prox=Punt;
` else *Lista=Punt;
}
22
Sommario
• Liste in C realizzate mediante puntatori
• Puntatori: struttura di basso livello ---> a rischio
• Liste: primo importante esempio di struttura dinamica
• Efficienza della struttura dinamica lista rispetto all’array:
• Pros: Si evita lo spreco di memoria/rischio di overflow
(obiettivo iniziale)
• Cons: Overhead 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
• Ricerca in una lista ordinata penalizzata dalla ricerca sequenziale.
23