Il tipo di dato astratto Pila

Transcript

Il tipo di dato astratto Pila
Il tipo di dato astratto
Pila
Il tipo di dato Pila
z
Una pila è una sequenza di elementi (tutti dello stesso tipo) in
cui l’inserimento e l’eliminazione di elementi avvengono secondo
la regola seguente:
z
L’elemento che viene eliminato tra quelli presenti nella pila deve essere
quello che è stato inserito per ultimo.
z
Si parla di gestione LIFO (per “Last In, First Out”).
z
Esempio: rappresentazione grafica di una pila
9
push 2
push 7
2
z
z
7
2
pop
push 5
2
5
2
push 9
5
2
L’elemento in cima alla pila viene detto elemento affiorante.
Una pila senza elementi viene detta pila vuota.
pop
5
2
2
1
Utilizzo delle pile
z
Uno degli utilizzi delle pile si ha nella soluzione di
problemi:
z
z
z
che richiedono di effettuare più scelte in successione, e
per cui può essere necessario ritrattare le scelte fatte per provare
altre alternative
z Æ si deve tornare indietro sull’ultima scelta fatta
(backtracking)
Si utilizza una pila per memorizzare la sequenza di
scelte fatte:
z
z
Push di una nuova scelta;
Pop ed eventuale Push della scelta alternativa quando si deve
fare backtracking.
3
Specifica del tipo di dato Pila
z
Domini di interesse:
z
Costanti:
z
Operazioni:
z TestPilaVuota : Pila Æ Booleano
z
Pila, Elemento, Booleano
PilaVuota
restituisce vero se la pila è vuota, falso altrimenti
z
TopPila : Pila Æ Elemento
z
Push : Pila x Elemento Æ Pila
z
z
z
restituisce l’elemento affiorante di una pila
inserisce un elemento in cima ad una pila e restituisce la pila
modificata
Pop : Pila Æ Pila x Elemento
z
estrae l’elemento affiorante dalla cima della pila e lo restituisce
(insieme alla pila modificata)
4
2
Realizzazione in C del tipo Pila
z
z
Indipendentemente da come verrà realizzato il tipo
astratto, si possono specificare i prototipi delle
funzioni che realizzano le diverse operazioni.
domini:
z
z
z
costanti:
z
z
typedef ... TipoElemPila;
typedef ... TipoPila;
void InitPila(TipoPila *pp);
operazioni:
z
z
z
z
int TestPilaVuota(TipoPila p);
void TopPila(TipoPila p, TipoElemPila *pv);
void Push(TipoPila *pp, TipoElemPila v);
void Pop(TipoPila *pp, TipoElemPila *pv);
5
Realizzazione in C del tipo Pila
z
Rappresentazione sequenziale
z
z
mediante vettori (statici o dinamici)
Rappresentazione collegata
z
Mediante strutture e puntatori
6
3
Realizzazione in C del tipo Pila:
confronti
z
z
z
Rappresentazione sequenziale statica:
z
+ implementazione semplice
z
+ può essere usata anche con linguaggi privi di allocazione dinamica della memoria
(ad es. FORTRAN)
z
- è necessario fissare a priori il numero massimo di elementi nella pila
z
- l’occupazione di memoria è sempre pari alla dimensione massima
Rappresentazione sequenziale dinamica:
z
+ pila può crescere indefinitamente
z
-le operazioni di Push e Pop possono richiedere la copia di tutti gli elementi presenti
nella pila Æ non sono più a tempo di esecuzione costante
Rappresentazione collegata:
z
+ pila può crescere indefinitamente
z
+ occupazione di memoria è proporzionale al numero di elementi nella pila
z
- maggiore occupazione di memoria dovuta ai puntatori
z
- implementazione leggermente più complicata
7
Rappresentazione sequenziale
z
Una pila è rappresentata mediante:
z
z
un vettore di elementi del tipo degli elementi della pila, riempito
fino ad un certo indice con gli elementi della pila
un indice che rappresenta la posizione nel vettore dell’elemento
affiorante della pila
9
2
5
9
?
?
?
?
?
?
5
0
1
2
3
4
5
6
7
8
2
z
z
2
p.pila
p.pos
Per la pila vuota: p.pos è pari a -1
È necessario fissare la dimensione del vettore a tempo di
compilazione. Si ha quindi un limite superiore al numero di elementi
nella pila
z Æ Si rende necessaria un’operazione di verifica di pila piena:
8
z int TestPilaPiena (TipoPila p);
4
Rappresentazione sequenziale (statica)
z
z
z
z
Dichiarazioni di tipo:
#define MaxPila 100
typedef ... TipoElemPila;
struct tipoPila {
TipoElemPila pila[MaxPila];
int pos;
};
typedef struct tipoPila TipoPila;
Inizializzazione di una pila:
void InitPila(TipoPila *pp){
(*pp).pos = -1;
}
Operazioni: sono tutte molto semplici e di costo costante
(ovvero indipendente dal numero di elementi nella pila)
Esercizio: studiare l’implementazione delle operazioni
9
Rappresentazione sequenziale (dinamica)
z
Per utilizzare un vettore senza dover fissare
la dimensione massima della pila a tempo di
compilazione si può utilizzare un vettore
allocato dinamicamente:
z
z
si fissa una dimensione iniziale del vettore (che determina
anche quella minima)
la dimensione può crescere e decrescere a seconda delle
necessità
10
5
Rappresentazione sequenziale (dinamica)
z
Dichiarazioni di tipo:
#define DimInizialePila 10
typedef ... TipoElemPila;
struct tipoPila {
TipoElemPila *pila;
int pos;
int dimCorrente;
};
typedef struct tipoPila TipoPila;
z
Inizializzazione di una pila:
richiede l’allocazione dinamica della memoria per il vettore
void InitPila(TipoPila *pp){
(*pp).pila = malloc(DimInizialePila * sizeof(TipoElemPila));
(*pp).pos = -1;
(*pp).dimCorrente = DimInizialePila;
}
z
Inserimento di un elemento: se la pila è piena bisogna aumentare la dimensione
del vettore (usando la funzione realloc)
11
Rappresentazione collegata
z
Una pila è rappresentata mediante una lista nella quale il primo
elemento è l’elemento affiorante della pila.
9
5
lis
9
5
2
2
z
z
Per rappresentare la pila vuota: lista vuota
Non è più necessario imporre un limite al numero massimo di elementi
nella pila.
z
z
z
z
z
Æ TestPilaPiena non serve più.
Anche in questo caso le funzioni sono molto semplici e di costo
costante:
Push: tramite un inserimento in testa ad una lista
Pop: tramite la cancellazione del primo elemento di una lista
Perchè non abbiamo usato una lista in cui l’elemento affiorante è
l’ultimo della lista?
12
6
Rappresentazione collegata
z
Dichiarazioni di tipo:
typedef ..... TipoElemPila;
typedef TipoElemPila TipoElemLista;
/* inclusione del file contenente la definizione del tipo TipoLista */
#include "tipolis.c"
typedef TipoLista TipoPila;
/* inclusione del file contenente l'implementazione delle
operazioni primitive sulle liste */
#include "liste.c"
13
Rappresentazione collegata
InitPila
/* inizializza la pila p ponendo a NULL il puntatore
all'elemento affiorante della pila */
void InitPila(TipoPila *p) {
InitLista(p);
}
TestPilaVuota
/* restituisce TRUE se la pila p e' vuota, FALSE altrimenti
*/
int TestPilaVuota(TipoPila p) {
return (TestListaVuota(p));
}
TopPila
/* restituisce in v l'elemento affiorante della pila p,
senza modificare la pila */
void TopPila(TipoPila p, TipoElemPila *v) {
TestaLista(p, v);
14
}
7
Rappresentazione collegata
Push
/* inserisce l'elemento v in cima alla pila p */
void Push(TipoPila *p, TipoElemPila v) {
InserisciTestaLista(p, v);
}
Pop
/* elimina l'elemento affiorante della pila p,
restituendone il valore in v */
void Pop(TipoPila *p, TipoElemPila *v) {
TopPila(*p, v);
CancellaPrimoLista(p);
}
z Esercizio: implementare tali funzioni operando direttamente sulla15
struttura a puntatori
8