Esercizio 11pila di code
In questa pagina 4
Testo (appello del 13 settembre 2017 di Fondamenti di Informatica, Ingegneria dell'Informazione UniPD; adattato da un tema d'esame in Java, qui in Python).
Una pila di code è una struttura che annida le caratteristiche dei due ADT pila e coda, con l'interfaccia:
| operazione | significato |
|---|---|
push(x) |
inserisce l'oggetto nella coda che si trova in cima alla pila |
pop() |
restituisce ed elimina l'oggetto inserito per primo nella coda in cima alla pila |
top() |
come pop() ma senza eliminarlo |
size() |
numero di elementi contenuti nella pila di code |
is_empty() |
vero se la pila di code è vuota |
Esempio: gli elementi da inserire, con code di taglia , finiscono così: , , . Estraendo tutti gli elementi l'ordine è . Con elementi la pila è composta da code da .
- Scrivere la classe
MiaPilaDiCodeche realizza l'interfaccia, con code di taglia massima 3. - Scrivere un programma di prova che crea una
MiaPilaDiCode, legge il fileinput.txtinserendo ogni riga nella pila di code, poi estrae tutti gli elementi mostrandoli sullo standard output.
Teoria: Pila e codaPila (LIFO) e coda (FIFO) come ADT: operazioni e costi; realizzazione in Python con list e collections.deque; realizzazione in C con array e indici, coda circolare; applicazioni (parentesi bilanciate, stack delle chiamate, visite).Pila e coda →, Classi ed ereditarietà in PythonAttributi di istanza e di classe, metodi di istanza, di classe e statici; confronto e ordinamento con eq e lt; proprietà; ereditarietà, super(), override e polimorfismo; classi astratte come interfacce; eccezioni personalizzate; overloading e shadowing in Python.Classi ed ereditarietà in Python →, Realizzare contenitori su array e listeCome si realizza un ADT contenitore partendo da un array: lunghezza logica e capacità con raddoppio (costo ammortizzato), dizionario su array ordinato con ricerca binaria, coda doppia su array circolare, coda con priorità a livelli, ADT costruiti sopra altri ADT (pila di code, pila reversibile); tabella dei costi.Realizzare contenitori su array e liste →.
Idea: ADT costruito sopra altri due ADT
Non serve un array: la struttura si ottiene componendo una pila e delle code (vedi Realizzare contenitori su array e listeCome si realizza un ADT contenitore partendo da un array: lunghezza logica e capacità con raddoppio (costo ammortizzato), dizionario su array ordinato con ricerca binaria, coda doppia su array circolare, coda con priorità a livelli, ADT costruiti sopra altri ADT (pila di code, pila reversibile); tabella dei costi.Realizzare contenitori su array e liste →).
- La pila è una
listusata solo in fondo (append,pop); i suoi elementi sono code (collections.deque, conappendin fondo epopleftdall'inizio). push(x): se non c'è nessuna coda, o quella in cima ha già 3 elementi, si apre una nuova coda in cima; poixsi accoda in fondo alla coda in cima.pop(): si toglie conpopleftil primo elemento della coda in cima (il più vecchio di quella coda); se la coda si svuota, va rimossa dalla pila: altrimentitopepushguarderebbero una coda vuota.top()leggecode[-1][0];sizesi tiene con un contatore (sommare le lunghezze costerebbe ).
Tutte le operazioni sono .
from collections import deque
class MiaPilaDiCode:
"""Pila le cui celle sono code di taglia massima K (qui 3)."""
K = 3
def __init__(self):
self._code = [] # pila di deque: la cima è l'ultima
self._n = 0
def push(self, x):
if not self._code or len(self._code[-1]) == self.K: # nessuna coda o coda in cima piena
self._code.append(deque())
self._code[-1].append(x) # in fondo alla coda in cima
self._n += 1
def pop(self):
x = self.top()
self._code[-1].popleft() # esce il PRIMO inserito della coda in cima
if not self._code[-1]:
self._code.pop() # coda esaurita: si toglie dalla pila
self._n -= 1
return x
def top(self):
if self._n == 0:
raise IndexError("pila di code vuota")
return self._code[-1][0]
def size(self):
return self._n
def is_empty(self):
return self._n == 0Programma di prova
import io
def main(f):
p = MiaPilaDiCode()
for riga in f:
p.push(riga.rstrip("\n")) # ogni riga del file nella pila di code
while not p.is_empty():
print(p.pop())
main(io.StringIO("a\nb\nc\nd\ne\n")) # con il file vero: main(open("input.txt"))Con le righe a b c d e (taglia 3) le code sono e : stampa d, e, a, b, c.
Verifica
p = MiaPilaDiCode()
for i in range(1, 10):
p.push(i)
print([len(c) for c in p._code], p.top(), p.size()) # [3, 3, 3] 7 9
usciti = []
while not p.is_empty():
usciti.append(p.pop())
print(usciti) # [7, 8, 9, 4, 5, 6, 1, 2, 3]
assert usciti == [7, 8, 9, 4, 5, 6, 1, 2, 3]
p = MiaPilaDiCode()
for i in range(21):
p.push(i)
print(len(p._code)) # 7 code da 3
p = MiaPilaDiCode()
for i in range(1, 5): # code: [1,2,3] [4]
p.push(i)
print(p.pop(), p.pop(), p.pop(), p.pop()) # 4 1 2 3
for i in (1, 2, 3, 4):
p.push(i) # [1,2,3] [4]
p.pop() # esce 4: la coda [4] viene eliminata
p.push(9) # la coda in cima è piena -> ne apre una nuova
print([list(c) for c in p._code]) # [[1, 2, 3], [9]]Errori comuni
- Non eliminare la coda svuotata:
top()darebbeIndexErrorpur con elementi nelle code sotto. - Estrarre dalla fine della coda (comportamento da pila) invece che dall'inizio (da coda).
- Aprire una nuova coda a ogni
push, o solo quando la pila è vuota, ignorando la taglia massima. - Contare gli elementi con
len(self._code)(numero di code) invece che con un contatore. - Ricostruire la struttura dopo ogni operazione: costo inutile.
Versione ripasso
Appello del 13 settembre 2017 (UniPD, in Java; adattato a Python). Teoria: Pila e codaPila (LIFO) e coda (FIFO) come ADT: operazioni e costi; realizzazione in Python con list e collections.deque; realizzazione in C con array e indici, coda circolare; applicazioni (parentesi bilanciate, stack delle chiamate, visite).Pila e coda →, Realizzare contenitori su array e listeCome si realizza un ADT contenitore partendo da un array: lunghezza logica e capacità con raddoppio (costo ammortizzato), dizionario su array ordinato con ricerca binaria, coda doppia su array circolare, coda con priorità a livelli, ADT costruiti sopra altri ADT (pila di code, pila reversibile); tabella dei costi.Realizzare contenitori su array e liste →.
Interfaccia: push(x) nella coda in cima; pop()/top() primo inserito della coda in cima; size, is_empty. Taglia massima 3: → , , ; estrazione .
Struttura: list di deque (la cima è l'ultima).
push: se non ci sono code o la coda in cima ha 3 elementi,append(deque()); poiappend(x)alla coda in cima.pop:popleftsulla coda in cima; se si svuota,popdalla pila.top:code[-1][0]; contatore_npersize. Tutto .
Prova: leggere input.txt riga per riga con push, poi pop fino a vuoto.
Errori comuni: coda vuota non eliminata; estrazione dalla fine; nuova coda a ogni push; size come numero di code.