Orario delle lezioni Strutture Dati LABORATORIO TEORIA martedì mercoledì 15.00 - 18.00 16.00 – 18.00 lab Turing aula P/4 Libro di testo Data Structures & Algorithms in Java Michael T. Goodrich Roberto Tamassia John Wiley & Sons, Inc. (quarta edizione) Strutture Dati Sito del corso http://www.dia.unisa.it/professori/demarco/sd/ Strutture Dati Esercitazioni integrative Dal 23 marzo: Corso integrativo di esercitazione Prof. Rosalba Zizza Venerdì dalle 9.00 alle 12.00 Laboratorio Reti Strutture Dati Strutture dati e tipi astratti di dati Algoritmo Struttura dati Informazione organizzata allo scopo di migliorare l'efficienza dell'algoritmo Tipo astratto di dati Definisce con rigore matematico una struttura dati Programma Strutture Dati Struttura dati implementata La struttura dati pila (stack) Inserimento, cancellazione e ricerca avvengono solo in una posizione inserimento e cancellazione avvengono secondo una strategia LIFO (last in first out): inserimento: un nuovo oggetto viene inserito in cima allo stack cancellazione: viene cancellato sempre l'oggetto in cima allo stack viene cancellato sempre l'oggetto che è stato inserito per ultimo Strutture Dati Il tipo astratto di dati (ADT) stack Tipo di dati e operazioni Dati: oggetti arbitrari (stringhe, interi, pezzi di codice, ...) Operazioni: - push (element): inserisce un elemento - element pop(): restituisce l'elemento inserito per ultimo e lo rimuove - element top(): restituisce l'elemento in cima - integer size(): restituisce il numero di elementi presenti - boolean isEmpty(): è vero se e solo se non ci sono elementi Strutture Dati Un esempio Operazione Strutture Dati Output Un esempio Operazione push(5) 5 Strutture Dati Output — Un esempio Operazione 8 5 Strutture Dati Output push(5) — push(8) — Un esempio Operazione 5 Strutture Dati Output push(5) — push(8) — pop() 8 Un esempio Operazione push(5) — push(8) — pop() 8 — push(3) 3 5 Strutture Dati Output Un esempio Operazione 5 Strutture Dati Output push(5) — push(8) — pop() push(3) 8 — pop() 3 Un esempio Operazione Strutture Dati Output push(5) — push(8) — pop() push(3) 8 — pop() 3 pop() 5 Un esempio Operazione Strutture Dati Output push(5) — push(8) — pop() push(3) 8 — pop() 3 pop() 5 pop() ? Il tipo astratto di dati (ADT) stack Eccezioni Qual è il risultato di un'operazione di pop() (o di top()) su uno stack vuoto? Strutture Dati Il tipo astratto di dati (ADT) stack Eccezioni Qual è il risultato di un'operazione di pop() (o di top()) su uno stack vuoto? Una exception si verifica quando un'operazione non può essere eseguita. Ad esempio: - top() su uno stack vuoto - pop() su uno stack vuoto Strutture Dati Applicazioni Cronologia pagine visitate con un navigatore web Ogni volta che viene visitato un nuovo sito, l'indirizzo del sito corrente viene inserito nello stack con un'operazione di push. Strutture Dati Applicazioni Cronologia pagine visitate con un navigatore web Ogni volta che viene visitato un nuovo sito, l'indirizzo del sito corrente viene inserito nello stack con un'operazione di push. Strutture Dati Applicazioni Cronologia pagine visitate con un navigatore web Ogni volta che viene visitato un nuovo sito, l'indirizzo del sito corrente viene inserito nello stack con un'operazione di push. In cima allo stack ci sarà sempre l'indirizzo dell'ultima pagina visitata La proprietà LIFO dello stack ci garantisce che il tasto back ci farà visualizzare le pagine in ordine cronologico inverso (dalla più recente alla più vecchia) Strutture Dati Applicazioni Cronologia pagine visitate con un navigatore web La pressione del tasto "back" del navigatore genera un'operazione di pop dello stack. Ogni volta che viene visitato un nuovo sito, l'indirizzo del sito corrente viene inserito nello stack con un'operazione di push. In cima allo stack ci sarà sempre l'indirizzo dell'ultima pagina visitata La proprietà LIFO dello stack ci garantisce che il tasto back ci farà visualizzare le pagine in ordine cronologico inverso (dalla più recente alla più vecchia) Strutture Dati Applicazioni Cronologia pagine visitate con un navigatore web La pressione del tasto "back" del navigatore genera un'operazione di pop dello stack. Ogni volta che viene visitato un nuovo sito, l'indirizzo del sito corrente viene inserito nello stack con un'operazione di push. Strutture Dati Implementazione stack Una semplice soluzione con array Siccome quando si crea un array è necessario definire la sua taglia (size), l'implementazione dello stack mediante array comporta la specifica della massima taglia N dello stack. Lo stack viene implementato con un array di N elementi e una variabile t che indica l'indice dell'elemento in cima allo stack top . . . 0 Strutture Dati 1 2 t N-1 Implementazione stack con array Pseudocodice dei metodi top . . . 0 1 2 Algorithm size(): return t + 1 Strutture Dati t N-1 Implementazione stack con array Pseudocodice dei metodi top . . . 0 1 2 Algorithm isEmpty(): return (t < 0) Strutture Dati t N-1 Implementazione stack con array Pseudocodice dei metodi top . . . 0 1 2 Algorithm top(): if isEmpty() then throw a EmptyStackException return S[t] Strutture Dati t N-1 Implementazione stack con array Pseudocodice dei metodi top . . . 0 1 2 Algorithm push(element): if size() = N then throw a FullStackException t := t + 1 S[t] := element Strutture Dati t N-1 Implementazione stack con array Vantaggi e svantaggi Vantaggi Implemetazione semplice ed efficiente Memoria usata: O(N) Complessità dei metodi (size, isEmpty, top, push, pop): O(1) Svantaggi Bisogna fissare a priori un limite superiore N alla massima taglia dello stack Un'applicazione potrebbe richiedere una capacità superiore ad N Lo Stack lancia una StackFullException che arresta l'applicazione Un'applicazione potrebbe richiedere una capacità molto inferiore ad N Spreco di memoria Strutture Dati La struttura dati coda (queue) Inserimento, cancellazione e ricerca avvengono solo in due posizioni inserimento e cancellazione avvengono secondo una strategia FIFO (first in first out): in inserimento: un nuovo oggetto viene inserito dietro la coda cancellazione: viene cancellato sempre l'oggetto davanti alla coda out Strutture Dati viene cancellato sempre l'oggetto che è stato inserito per primo Il tipo astratto di dati coda (queue) Tipo di dati e operazioni Dati: oggetti arbitrari Operazioni: - void enqueue (element): inserisce un nuovo elemento dietro (rear) la coda - element dequeue(): restituisce l'elemento in testa (front) alla coda (quello che è stato più a lungo in coda) e lo rimuove - element front(): restituisce l'elemento in testa alla coda - integer size(): restituisce il numero di elementi presenti in coda - boolean isEmpty(): è vero se e solo se non ci sono elementi in coda Strutture Dati Il tipo astratto di dati coda (queue) Un esempio 5 Strutture Dati Operazione Output enqueue(5) — Il tipo astratto di dati coda (queue) Un esempio 8 5 Strutture Dati Operazione Output enqueue(5) — enqueue(8) — Il tipo astratto di dati coda (queue) Un esempio 8 Strutture Dati Operazione Output enqueue(5) — enqueue(8) — dequeue() 5 Il tipo astratto di dati coda (queue) Un esempio 6 8 Operazione Output enqueue(5) — enqueue(8) — dequeue() enqueue(6) Strutture Dati 5 — Il tipo astratto di dati coda (queue) Un esempio 6 Operazione Output enqueue(5) — enqueue(8) — dequeue() enqueue(6) dequeue() Strutture Dati 5 — 8 Il tipo astratto di dati coda (queue) Un esempio Operazione Output enqueue(5) — enqueue(8) — dequeue() enqueue(6) Strutture Dati 5 — dequeue() 8 dequeue() 6 Il tipo astratto di dati coda (queue) Un esempio Operazione Output enqueue(5) — enqueue(8) — dequeue() enqueue(6) Strutture Dati 5 — dequeue() 8 dequeue() 6 dequeue() error Il tipo astratto di dati coda (queue) Le eccezioni Ricordare: una exception si verifica quando un'operazione non può essere eseguita. Ad esempio: - front() su una coda vuota - dequeue() su una coda vuota Strutture Dati Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Problema: come fare dequeue? Strutture Dati N-1 Implementazione coda Una semplice soluzione con array front rear . . . 0 1 2 N-1 Come tenere traccia di front e rear della coda? - Q[0] contiene la testa della coda (front) - inseriamo gli oggetti da sinistra a destra - una variabile rear indica la prima cella libera Questa soluzione non è efficiente perché in caso di dequeue si dovranno spostare tutti i rimanenti oggetti di una posizione a sinistra: ciò richiede complessità O(n), dove n è il numero di oggetti in coda Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) Definiamo due variabili f e r : All'inizio f = r = 0 (la coda è vuota) f=r=0 . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) f r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) f r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) f r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) f r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) f r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) Ora f = r (la coda è vuota) f=r . . . 0 1 2 N-1 - quando aggiungiamo un elemento, basterà incrementare r fino alla prossima cella disponibile - quando cancelliamo un elemento, basterà spostare f alla cella successiva Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) . . . 0 1 2 N-1 In generale: se la coda è vuota: f= r se la coda non è vuota: - f è l'indice della cella che contiene il primo elemento della coda (front) - r è l'indice della cella dove verrà inserito il prossimo elemento della coda Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) Inconveniente n. 1 Situazione dopo una serie di N enqueue e dequeue consecutive: f=r=N -1 . . . 0 1 2 N-1 La coda è vuota ma lo spazio a disposizione sull'array è finito Se ora volessimo inserire un elemento nella coda, dovremmo incrementare r , ma ciò non è permesso perché r ha già raggiunto il limite massimo consentito dalla taglia dell'array Strutture Dati Implementazione coda Un'altra soluzione con array (più efficiente) Per evitare il problema f ed r possono essere incrementati "circolarmente" f=r=N -1 . . . 0 1 2 Incremento di f: f = ( f + 1) mod N Incremento di r: r = ( r + 1) mod N Strutture Dati N-1 quando f = r la coda è vuota Implementazione coda Un'altra soluzione con array (più efficiente) Inconveniente n. 2 Situazione dopo una successione di N enqueue consecutive: f=r . . . 0 1 2 N-1 Questa condizione corrisponde alla situazione di coda vuota! Si può ovviare ponendo a N - 1 il limite massimo di oggetti che la coda può contenere Strutture Dati Implementazione coda con array Pseudocodice dei metodi f r . . . 0 1 2 N-1 r f . . . 0 1 2 Algorithm size(): return (N + r - f) mod N Strutture Dati N-1 Implementazione coda con array Pseudocodice dei metodi f r . . . 0 1 2 Algorithm isEmpty(): return (f = r) Strutture Dati N-1 Implementazione coda con array Pseudocodice dei metodi f r . . . 0 1 2 Algorithm front(): if isEmpty() then throw a EmptyQueueException return Q[f] Strutture Dati N-1 Implementazione coda con array Pseudocodice dei metodi f r . . . 0 1 2 Algorithm dequeue(): if isEmpty() then throw a EmptyQueueException temp := Q[f] Q[f] := null f := (f+1) mod N return temp Strutture Dati N-1 Implementazione coda con array Pseudocodice dei metodi f r . . . 0 1 2 Algorithm enqueue(element) if size() = N - 1 then throw a FullQueueException Q[r ] := element r := (r + 1) mod N Strutture Dati N-1 Implementazione coda con array Vantaggi e svantaggi Vantaggi Implemetazione semplice ed efficiente Memoria usata: O(N) Complessità dei metodi (size, isEmpty, front, enqueue, dequeue): O(1) Svantaggi Bisogna fissare a priori un limite superiore N alla massima taglia della coda Strutture Dati