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