Ordinamenti e crescita della complessità

Documenti analoghi
1 Definizione di sistema lineare omogeneo.

Somma di numeri floating point. Algoritmi di moltiplicazione e divisione per numeri interi

SISTEMI LINEARI. x 2y 2z = 0. Svolgimento. Procediamo con operazioni elementari di riga sulla matrice del primo sistema: R 2 R 2 3R

Vettori e matrici. Lorenzo Pareschi. Dipartimento di Matematica & Facoltá di Architettura Universitá di Ferrara

Heap e code di priorità

Laboratorio di Architettura lezione 5. Massimo Marchiori W3C/MIT/UNIVE

Macchine RAM. API a.a. 2013/2014 Gennaio 27, 2014 Flavio Mutti, PhD

INDICAZIONI PER LA RICERCA DEGLI ASINTOTI VERTICALI

1 L estrazione di radice

Informatica Teorica. Macchine a registri

VBA è un linguaggio di scripting derivato da Visual Basic, da cui prende il nome. Come ogni linguaggio ha le sue regole.

Prof.ssa Laura Salvagno

Potenze - Monomi - Polinomi - Operazioni tra Polinomi - Quadrato e Cubo del Binomio - Quadrato del Trinomio

PROGRAMMAZIONE STRUTTURATA

Mini-Corso di Informatica

STATISTICHE DESCRITTIVE Parte II

Il concetto di calcolatore e di algoritmo

2.3 Cammini ottimi. E. Amaldi Fondamenti di R.O. Politecnico di Milano 1

Informatica/ Ing. Meccanica/ Prof. Verdicchio/ 14/02/2012 / Foglio delle domande / VERSIONE 1

Il calcolatore. Architettura di un calcolatore (Hardware)

Strutture dati e algoritmi. Sommario

Lezione 4. Sommario. L artimetica binaria: I numeri relativi e frazionari. I numeri relativi I numeri frazionari

Esercizi svolti. risolvere, se possibile, l equazione xa + B = O, essendo x un incognita reale

Appunti di informatica. Lezione 4 anno accademico Mario Verdicchio

I diversi modi di contare

Corso di Fondamenti di Informatica

Numeri frazionari. sistema posizionale. due modi: virgola fissa virgola mobile. posizionale, decimale

Array multidimensionali e stringhe

Procedura operativa per la gestione della funzione di formazione classi prime

Esempio : i numeri di Fibonacci

ADT Coda con priorità

UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA. Matlab: esempi ed esercizi

Introduzione alle macchine a stati (non definitivo)

Equazione della circonferenza

La riduzione a gradini e i sistemi lineari (senza il concetto di rango)

Anno 2. Circonferenza e retta: definizioni e proprietà

Daniela Lera A.A

Codifica dei Numeri. Informatica ICA (LC) 12 Novembre 2015 Giacomo Boracchi

Metodo di Gauss-Jordan 1

Linguaggi e Grammatiche Liberi da Contesto

Codice Gray. (versione Marzo 2007)

Corso di Fondamenti di Informatica Classi di istruzioni 2

M n a u n a u l a e l e o p o e p r e a r t a i t v i o v o Ver /12/2014

11.4 Chiusura transitiva

Diagrammi a blocchi 1

Anno 3. Funzioni esponenziali e logaritmi: le 4 operazioni

Matematica con il foglio di calcolo

PARTE III MACCHINE A REGISTRI

Algoritmi. Un tema centrale dell informatica è lo studio degli algoritmi.

I RADICALI QUADRATICI

Funzioni elementari: funzioni potenza

Teoria dei Giochi Prova del 9 Settembre se tutti i giocatori scelgono lo stesso numero, il payoff è zero per ciascun giocatore;

4 0 = 4 2 = 4 4 = 4 6 = 0.

Laboratorio di Programmazione Lezione 1. Cristian Del Fabbro

Lezione 2. Sommario. Il sistema binario. La differenza Analogico/Digitale Il sistema binario

Algoritmi e Strutture Dati

Progettazione di Algoritmi

PSICOMETRIA. Esercitazione n.1. C.d.L. Comunicazione e Psicologia a.a. 2012/13

Informatica B. Sezione D. Scuola di Ingegneria Industriale Laurea in Ingegneria Energetica Laurea in Ingegneria Meccanica

7 Cenni di ottica per la fotografia

Fortran in pillole : prima parte

La codifica. dell informazione

Definizione: Dato un sottoinsieme non vuoti di. Si chiama funzione identica o identità di in sé la funzione tale che.

Introduzione a Visual Basic Lezione 2 Cicli e anomalie

Risoluzione di problemi ingegneristici con Excel

Rappresentazioni numeriche

Congruenze. Trovare la cifra dell unità dei seguenti numeri [3] [6] [5]

SISTEMI LINEARI MATRICI E SISTEMI 1

Esercizi sui sistemi di equazioni lineari.

FUNZIONI ELEMENTARI, DISEQUAZIONI, NUMERI REALI, PRINCIPIO DI INDUZIONE Esercizi risolti

x 2 + (x+4) 2 = 20 Alle equazioni di secondo grado si possono applicare i PRINCIPI di EQUIVALENZA utilizzati per le EQUAZIONI di PRIMO GRADO.

ESPONENZIALI E LOGARITMI. chiameremo logaritmica (e si legge il logaritmo in base a di c è uguale a b ).

Algebra di Boole Algebra di Boole

Costruiamo la STRISCIA DELLE MISURE. decametro metro decimetro. Tm Gm Mm km hm dam m dm cm mm µm nm pm

Richiami di aritmetica(2)

Definizione. Il valore assoluto lascia inalterato ciò che è già positivo e rende positivo ciò che positivo non è.

Cercare il percorso minimo Ant Colony Optimization

Riconoscere e formalizzare le dipendenze funzionali

Macchina di Turing ... !!... !!! a b b! b a! Nastro di Input. testina. s t q i. s r. Unità di Controllo q j S / D / F

METODI E TECNOLOGIE PER L INSEGNAMENTO DELLA MATEMATICA. Lezione n

Bono Marco Spirali triangolari e quadrate 1. Spirali triangolari e quadrate

I coefficienti delle incognite sono proporzionali fra loro ma NON coi termini noti, e il sistema è dunque IMPOSSIBILE (si dice anche: INCOMPATIBILE).

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1

Equazioni, funzioni e algoritmi: il metodo delle secanti

LEZIONE 3. Typeset by AMS-TEX

ESERCIZI DEL CORSO DI INFORMATICA

7 Disegni sperimentali ad un solo fattore. Giulio Vidotto Raffaele Cioffi

Esercitazioni di Reti Logiche. Lezione 1 Rappresentazione dell'informazione. Zeynep KIZILTAN zkiziltan@deis.unibo.it

0.1 Esercizi calcolo combinatorio

PROGRAMMA DI SCIENZE E TECNOLOGIE APPLICATE 2015/2016 Classe 2ª Sez. C Tecnologico

EXCEL. Alfabetizzazione Informatica Prof. GIUSEPPE PATTI

Modulo 2 Data Base - Modello Relazionale

Disequazioni in una incognita. La rappresentazione delle soluzioni

Laboratorio di Programmazione Appunti sulla lezione 4: Divide et impera e algoritmi di ordinamento

REGOLE DI BASE DEL GIOCO DEGLI SCACCHI

C I R C O N F E R E N Z A...

3. Matrici e algebra lineare in MATLAB

Architettura dei computer

Esercitazione 4. Comandi iterativi for, while, do-while

Le equazioni di I grado

Transcript:

Ordinamenti e crescita della complessità Informatica@SEFA 07/08 - Lezione Massimo Lauria <massimo.lauria@uniroma.it> Venerdì, 7 Ottobre 07 Nota bibliografica: Il contenuto di questa e di alcune delle prossime lezioni può essere trovato nei primi capitoli del libro Introduzione agli Algoritmi e strutture dati (Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein). Tuttavia il libro è grosso e costoso, quindi cerco di mettere tutto il materiale negli appunti del corso. La misura della complessità computazionale Quando consideriamo le prestazioni di un algoritmo non vale la pena considerare l effettivo tempo di esecuzione o la quantità di RAM occupate. Queste cose dipendono da caratteristiche tecnologiche che niente hanno a che vedere con la qualità dell algoritmo. Al contrario è utile considerare il numero di operazioni elementari che l algoritmo esegue. accessi in memoria operazioni aritmetiche ecc... Che cos è un operazione elementare? Per essere definiti, questi concetti vanno espressi su modelli computazionali formali e astratti, sui quali definire gli algoritmi che vogliamo misurare. Per noi tutto questo non è necessario. Ci basta capire a livello intuitivo il numero di operazioni elementari che i nostri algoritmi fanno per ogni istruzione. http://massimolauria.net/courses/infosefa07/

Esempi una somma di due numeri float : op. verificare se due numeri float sono uguali: op. confronto lessicografico tra due stringhe di lunghezza n: n op. ricerca lineare in una lista Python di n elementi: n op. ricerca binaria in una lista ordinata di n elementi: log n op. inserimento nella 4a posizione in una lista di n elementi: n op. seq[a:b] : b a operazioni seq[:] : len(seq) operazioni seq + seq : len(seq) + len(seq) operazioni Un algoritmo di ordinamento: Insertion sort Nella lezione precedente abbiamo visto due tipi di ricerca. Quella sequenziale o lineare e quella binaria. Per utilizzare la ricerca binaria è necessario avere la sequenza di dati ordinata. Oggi vedremo un semplice algoritmo di ordinamento. non è molto efficiente semplice da realizzare L idea dell insertion sort è simile a quella di una persona che gioca a carte e che vuole ordinare la propria mano. Prende la carta più piccola e la sposta all inizio. Poi prende la carta più piccola tra le rimanenti e la mette alla seconda posizione, poi la più piccola tra le rimanenti va in terza posizione e così via... In sostanza se una sequenza ha n elementi, l insertion sort fa n iterazioni per i da 0 a n. In ognuna: si calcola il minimo tra gli elementi della sequenza nelle posizioni i... n ; si sposta il minimo nella posizione i, traslando gli elementi nella sequenza per fagli spazio.

Per prima cosa vediamo come trovare il minimo di una sequenza. La funzione min di Python non è sufficiente, perché non restituisce la posizione dell elemento. def argmin(seq,start,end): minimo = seq[start] indice = start for i in range(start+,end+): if seq[i] < minimo: minimo = seq[i] indice = i return minimo,indice 4 5 6 7 8 Poi scriviamo una funzione che sposta tutti di elementi in un intervallo della lista di una posizione verso destra. def moveright(seq,start,end): for i in range(end,start -,-): seq[i+] = seq[i] def insertion_sort(seq): for i in range(0,len(seq) -): val,pos = argmin(seq,i,len(seq) -) moveright(seq,i,pos -) seq[i] = val 4 5 6 7 8 Vediamo un esempio con una sequenza arbitraria dati = [,-4,,6,,-5,9] insertion_sort(dati) Step 0: [, -4,, 6,, -5, 9] Step : [-5,, -4,, 6,, 9] Step : [-5, -4,,, 6,, 9] Step : [-5, -4,,,, 6, 9] Step 4: [-5, -4,,,, 6, 9] Step 5: [-5, -4,,, 6,, 9] Step 6: [-5, -4,,, 6, 9, ] In realtà potremmo usare un trucco. Magari lo vediamo dopo se avanza tempo.

Vediamo un esempio con una sequenza invertita dati = [0,9,8,7,6,5,4,,,] insertion_sort(dati) Step 0: [0, 9, 8, 7, 6, 5, 4,,, ] Step : [, 0, 9, 8, 7, 6, 5, 4,, ] Step : [,, 0, 9, 8, 7, 6, 5, 4, ] Step : [,,, 0, 9, 8, 7, 6, 5, 4] Step 4: [,,, 4, 0, 9, 8, 7, 6, 5] Step 5: [,,, 4, 5, 0, 9, 8, 7, 6] Step 6: [,,, 4, 5, 6, 0, 9, 8, 7] Step 7: [,,, 4, 5, 6, 7, 0, 9, 8] Step 8: [,,, 4, 5, 6, 7, 8, 0, 9] Step 9: [,,, 4, 5, 6, 7, 8, 9, 0] Quante operazioni esegue l insertion sort? Per ogni ciclo i, con i da 0 a n, l algoritmo trova il minimo su una sequenza di n i elementi. Poi sposta tutti gli elementi tra quell $i$-esimo e la posizione del minimo a quel ciclo. Il numero esatto di spostamenti dipende da dove era collocato il minimo. In ogni caso alla peggio sono n i spostamenti. Dunque in totale sono al massimo n (n i) i 0 n i n(n + ) n () i Esercizio: per quali input il numero di operazioni è maggiore? Vale la pena ordinare prima di fare ricerche? Abbiamo visto che t ricerche costano nt se si utilizza la ricerca sequenziale. E se vogliamo utilizzare insertion sort seguito da ricerche binarie? Il costo è n + t log n, che è comparabile con nt solo se si effettuano almeno t n ricerche. Una piccola variazione Eseguiamo una piccola variazione dell insertion sort, che differisce per due caratteristiche: 4

al passo i mettiamo il massimo elemento alla posizione n i; la ricerca del massimo ed il suo spostamento alla fine nella lista sono fatte simultaneamente. Vediamo ad esempio come funziona il primo passo: cominciando dall inizio si confrontano i primi due elementi adiacenti. Se il primo è più grande del secondo, i due elementi si invertono. Poi si passa al second ed al terzo. Poi al terzo con il quarto, e così via. def bubbleup(seq,end,log=false): for i in range(0,end): # si ferma a end - seq[i], seq[i+] = min(seq[i],seq[i+]),max(seq[i],seq[i+]) bubbleup([5,-4,,6,9,,-5],6, log=true) Step 0: [5, -4,, 6, 9,, -5] Step : [-4, 5,, 6, 9,, -5] Step : [-4,, 5, 6, 9,, -5] Step : [-4,, 5, 6, 9,, -5] Step 4: [-4,, 5, 6, 9,, -5] Step 5: [-4,, 5, 6,, 9, -5] Step 6: [-4,, 5, 6,, -5, 9] Notate come il massimo sia messo sul fondo della lista, ma al contrario di insertion sort, gli altri elementi potrebbero aver cambiato il loro ordine. L ordinamento finale si ottiene ripetendo la procedura, ma al passo i si opera solo sulla sottolista degli elementi dalla posizione 0 alla posizione n i. def stupid_bubblesort(seq): for i in range(,len(seq)): bubbleup(seq,len(seq)-i) Vediamo un esempio casuale stupid_bubblesort([5,-4,,6,9,,-5]) Step 0: [5, -4,, 6, 9,, -5] Step : [-4,, 5, 6,, -5, 9] Step : [-4,, 5,, -5, 6, 9] Step : [-4,,, -5, 5, 6, 9] Step 4: [-4,, -5,, 5, 6, 9] Step 5: [-4, -5,,, 5, 6, 9] Step 6: [-5, -4,,, 5, 6, 9] stupid_bubblesort([0,9,8,7,6,5,4,,,]) 5

Step 0: [0, 9, 8, 7, 6, 5, 4,,, ] Step : [9, 8, 7, 6, 5, 4,,,, 0] Step : [8, 7, 6, 5, 4,,,, 9, 0] Step : [7, 6, 5, 4,,,, 8, 9, 0] Step 4: [6, 5, 4,,,, 7, 8, 9, 0] Step 5: [5, 4,,,, 6, 7, 8, 9, 0] Step 6: [4,,,, 5, 6, 7, 8, 9, 0] Step 7: [,,, 4, 5, 6, 7, 8, 9, 0] Step 8: [,,, 4, 5, 6, 7, 8, 9, 0] Step 9: [,,, 4, 5, 6, 7, 8, 9, 0] Vediamo un esempio ordinato in maniera opposta. Step 0: [0, 9, 8, 7, 6, 5, 4,,, ] Step : [9, 8, 7, 6, 5, 4,,,, 0] Step : [8, 7, 6, 5, 4,,,, 9, 0] Step : [7, 6, 5, 4,,,, 8, 9, 0] Step 4: [6, 5, 4,,,, 7, 8, 9, 0] Step 5: [5, 4,,,, 6, 7, 8, 9, 0] Step 6: [4,,,, 5, 6, 7, 8, 9, 0] Step 7: [,,, 4, 5, 6, 7, 8, 9, 0] Step 8: [,,, 4, 5, 6, 7, 8, 9, 0] Step 9: [,,, 4, 5, 6, 7, 8, 9, 0] Notazione asintotica Quando si contano il numero di operazioni in un algoritmo, non è necessario essere estremamente precisi. A che serve distinguere tra 0n operazioni e n operazioni se in un linguaggio di programmazione le 0n operazioni sono più veloci delle n operazioni implementate in un altro linguaggio? Al contrario é molto importante distinguere, ad esempio, 00 n operazioni da 0 n operazioni. Anche una macchina più veloce paga un prezzo alto se esegue un algoritmo da 00 n operazioni invece che uno da 00 n. Oltretutto un algoritmo asintoticamente più veloce spesso paga un prezzo più alto in fase di inizializzazione (per esempio perché deve sistemare i dati in una certa maniera). Dunque ha senso fare un confronto solo per lunghezze di input grandi abbastanza. Per discutere in questi termini utilizziamo la notazione asintotica che è utile per indicare quanto cresce il numero di operazioni di un algoritmo, al crescere della lunghezza dell input. Definizione: date f : N N e g : N N diciamo che f O(g) 6

se esistono c > 0 e n 0 tali che f (n) c g(n) per ogni n > n 0. la costante c serve a ignorare la dimensione atomica delle operazioni. n 0 serve a ignorare i valori piccoli di n. Ad esempio n 00 + n 0 è in O(n ), non è in O(n l ) per nessun l < ed è in O(n l ) per l >. Complessità di un algoritmo: dato un algoritmo A consideriamo il numero di operazioni t A (x) eseguite da A sull input x {0, }. Per ogni taglia di input n possiamo definire il costo nel caso peggiore come c A (n) : max x {0,} n t A(x). Diciamo che un algoritmo A ha complessità O(g) se il suo costo nel caso peggiore c A O(g). Per esempio abbiamo visto due algoritmi di ricerca (ricerca lineare e binaria) che hanno entrambi complessità O(n), ed il secondo ha anche complessità O(log n). La notazione O(g) quindi serve a dare un approssimativo limite superiore al numero di operazioni che l algoritmo esegue. Esercizio: osservare che per ogni < a < b, log a (n) O(log b (n)); e log b (n) O(log a (n)). Quindi specificare la base non serve. Definizione (Ω e Θ): date f : N N e g : N N diciamo che f Ω(g) se esistono c > 0 e n 0 tali che f (n) c g(n) per ogni n > n 0. Diciamo anche che f Θ(g) se f Ω(g) e f O(g) simultaneamente. Complessità di un algoritmo (II): dato un algoritmo A consideriamo ancora il costo nel caso peggiore di A su input di taglia n come c A (n) : max x {0,} n t A(x). Diciamo che un algoritmo A ha complessità Ω(g) se c A Ω(g), e che ha complessità Θ(g) se c A Θ(g). 7

Per esempio abbiamo visto due algoritmi di ricerca (ricerca lineare e binaria) che hanno entrambi complessità Ω(log n), ed il primo anche complessità Ω(n). Volendo essere più specifici possiamo dire che la ricerca lineare ha complessità Θ(n) e quella binaria ha complessità Θ(log n). Fate attenzione a questa differenza: se A ha complessità O(g), allora A gestisce tutti gli input con al massimo g operazioni circa, asintoticamente. se A ha complessità Ω(g), allora esiste una famiglia infinita di input tali che A richiede almeno g operazioni circa. Note su come misuriamo la lunghezza dell input Gli ordini di crescita sono il linguaggio che utilizziamo quando vogliamo parlare dell uso di risorse computazionali, indicando come le risorse crescono in base alla dimensione dell input. La lunghezza dell input n consiste nel numero di bit necessari a codificarlo. Tuttavia per problemi più specifici è utile, e a volte più comodo, indicare con n la dimensione "logica" dell input. Ad esempio: trovare il massimo in una sequenza. n sarà la quantità di numeri nella sequenza. trovare una comunità in una rete sociale con x nodi, e y connessioni. La lunghezza dell input può essere sia x che y a seconda dei casi. Moltiplicare due matrici quadrate n n. La dimensione dell input è il numero di righe (o colonne) delle due matrici. Naturalmente misurare così la complessità ha senso solo se consideriamo, ad esempio, dati numerici di grandezza limitata. Ovvero numeri di grandezza tale che le operazioni su di essi possono essere considerate atomiche senza l analisi dell algoritmo ne sia influenzata. Esercitarsi sulla notazione asintotica Ci sono alcuni fatti ovvi riguardo la notazione asintotica, che seguono immediatamente le definizioni. Dimostrate che 8

. per ogni 0 < a < b, n a O(n b ), n b O(n a );. per ogni 0 < a < b, n b Ω(n a ), n a Ω(n b );. se f Ω(h) allora f g Ω(h g); 4. se f O(h) allora f g O(h g); 5. che (n + a) b Θ(n b ). 6. preso un qualunque polinomio p d i 0 α ix i si ha che p(n) Θ(n d ); 7. che n! Ω( n ) ma che n! O( n ); 8. che ( n d) n d. 9