Esercizio 5crescita delle funzioni e costo degli algoritmi
In questa pagina 10
Testo (questionario di dicembre 2022 e test d'esame di dicembre 2012 e gennaio 2014 del corso di Fondamenti di Informatica UniPD; i quesiti sono indipendenti dal linguaggio). Teoria: Complessità computazionaleCosto di un algoritmo in funzione della dimensione dell'input; caso peggiore, migliore e medio; notazione O-grande e classi di crescita; come contare i passi di cicli e ricorsioni; costo delle operazioni Python.Complessità computazionale →, Algoritmi di ordinamentoSelection sort e insertion sort (quadratici, con invarianti), merge sort (divide et impera, Theta(n log n)), quick sort (caso pessimo quadratico, medio n log n), heap sort (in loco, Theta(n log n)), ordinamento senza confronti per chiavi intere in un intervallo piccolo, limite inferiore Omega(n log n) per gli algoritmi basati su confronti.Algoritmi di ordinamento →, Ricerca lineare e binariaRicerca lineare su sequenze qualsiasi in O(n); ricerca binaria su sequenze ordinate in O(log n), versione iterativa e ricorsiva, invariante e errori di indice; modulo bisect.Ricerca lineare e binaria →.
- Qual è la miglior stima asintotica di ?
- Della funzione dire se è , , , .
- Ordinare per complessità crescente , , .
- Se l'ordinamento per selezione di elementi richiede secondi, quanto servirà per elementi?
- Quale tra con tempo e con tempo è migliore asintoticamente?
- Se , quali delle seguenti affermazioni sono sempre vere: ; ; ; ?
- Un vettore dinamico raddoppia la capacità quando è pieno. Quante copie di elementi si fanno in inserimenti? E se la capacità cresce di una sola unità alla volta? Che cosa significa " ammortizzato"?
- Un programma usa una lista Python come coda: inserisce con
appended estrae conpop(0). Quanto costa svuotarla, e concollections.deque?
1.
Si guarda il termine che cresce più in fretta e si trascurano costanti e termini di ordine inferiore:
- cresce lentamente;
- : ;
- : una costante.
Quindi . Numericamente tende a (con vale ).
2.
Dominante: (gli altri termini sono , e una costante: ). Dunque:
- : vera;
- : vera (cresce almeno come );
- : vera (è un limite superiore non stretto);
- : falsa, perché cresce più di .
Un'affermazione è un limite superiore, non necessariamente stretto: è vero ma poco informativo.
3. Ordine
: .
4. Ordinamento per selezione
L'ordinamento per selezione fa confronti. Con il tempo si moltiplica per (esattamente ): 1000 secondi. (Con mergesort, , il fattore sarebbe circa .)
5. e
: per grande il rapporto ( per ; per , dove il termine pesa). Entrambi sono : dal punto di vista asintotico sono equivalenti. Le costanti ( contro ) e i termini lineari non contano nella notazione .
6. Conseguenze di
- : sempre vera (un limite più largo);
- : sempre vera;
- : non è detto ( la smentisce);
- : non è detto ( è ma non ).
dà un limite dall'alto, dal basso, i due insieme.
7. Vettore dinamico e costo ammortizzato
Una append che trova il vettore pieno copia tutti gli elementi. Con raddoppio le copie avvengono quando : in inserimenti sono . Con incremento di 1 si copia a ogni inserimento: .
| copie con raddoppio | copie con | copie con | ||
|---|---|---|---|---|
| 100 | 127 | 4950 | 460 | 200 |
| 1000 | 1023 | 499 500 | 49 600 | 2000 |
| 10 000 | 16 383 | 49 995 000 | 4 996 000 | 20 000 |
Costo ammortizzato : il costo totale di operazioni è ( copie più scritture), cioè per operazione in media sulla sequenza, anche se una singola operazione può costare . Non è una media su input casuali: vale nel caso peggiore, per qualsiasi sequenza. Un incremento costante non basta: il totale resta quadratico.
8. Coda su lista
pop(0) rimuove il primo elemento e sposta tutti gli altri di un posto: . Svuotare una lista di elementi costa spostamenti ( per , per : il doppio dei dati, quattro volte il lavoro). deque.popleft() è e svuotare la coda costa (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 →).
Verifica
import math
def copie(m, nuova_cap):
"""numero di elementi copiati in m inserimenti; nuova_cap(cap) = capacità dopo la crescita"""
cap, n, tot = 1, 0, 0
for _ in range(m):
if n == cap:
tot += n
cap = nuova_cap(cap)
n += 1
return tot
for m in (100, 1000, 10000):
print(m, copie(m, lambda c: 2 * c), copie(m, lambda c: c + 1), copie(m, lambda c: c + 10), 2 * m)
f = lambda n: math.log(n) + 2 * n * math.log(n + 4) + (3 * n + 1) * (n - 1) / n ** 2
print(f(10 ** 6) / (10 ** 6 * math.log(10 ** 6))) # 2.0000017962...
T = lambda n: 3 * n + 10 * math.log(math.log(n)) + n * math.log(n) + 8
print(T(10 ** 8) / (10 ** 8 * math.log(10 ** 8))) # 1.1628...: tende a 1
sel = lambda n: n * (n - 1) // 2 # confronti del selection sort
print(sel(10 ** 5) / sel(10 ** 4)) # 100.009
A0 = lambda n: 5 * n * n
A1 = lambda n: n * (n - 1000) + 7 * n
print(A1(10 ** 7) / A0(10 ** 7)) # 0.19998...: costante, stesso ordine
spostamenti = lambda n: sum(n - 1 - i for i in range(n)) # svuotare una lista con pop(0)
print(spostamenti(1000), spostamenti(2000)) # 499500 1999000Errori comuni
- Tenere le costanti o i termini di ordine inferiore nella risposta ( invece di ).
- Confondere (limite superiore) con (limite stretto).
- Dire che un algoritmo "da " è peggiore di uno "da ": stessa classe di crescita.
- Credere che ammortizzato voglia dire "veloce in media su dati casuali".
- Usare
list.pop(0)per fare una coda.
Versione ripasso
Questionario di dicembre 2022 e test di dicembre 2012 e gennaio 2014 (UniPD). Teoria: Complessità computazionaleCosto di un algoritmo in funzione della dimensione dell'input; caso peggiore, migliore e medio; notazione O-grande e classi di crescita; come contare i passi di cicli e ricorsioni; costo delle operazioni Python.Complessità computazionale →, Algoritmi di ordinamentoSelection sort e insertion sort (quadratici, con invarianti), merge sort (divide et impera, Theta(n log n)), quick sort (caso pessimo quadratico, medio n log n), heap sort (in loco, Theta(n log n)), ordinamento senza confronti per chiavi intere in un intervallo piccolo, limite inferiore Omega(n log n) per gli algoritmi basati su confronti.Algoritmi di ordinamento →.
- Si tiene il termine dominante, senza costanti: (l'ultimo termine tende a 3). : , , ; non .
- Ordine crescente: .
- Selezione : moltiplica il tempo per 100 (); mergesort per .
- e sono entrambi : equivalenti asintoticamente.
- implica e , non né .
- Vettore dinamico: raddoppio → in inserimenti copie, ammortizzato (vale nel caso peggiore per ogni sequenza); incremento costante → copie (: 1023 contro 499 500).
list.pop(0)è : svuotare la lista costa ;deque.popleft()(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 →).
Errori comuni: costanti nel risultato; confuso con ; "peggiore" di ; ammortizzato inteso come caso medio; pop(0) per le code.