 
                                Informazioni generali  Luca Becchetti  Tel.: 06 49918335  Email: [email protected]  URL:  Testo adottato:   www.dis.uniroma1.it/~becchett  Ricevimento:  Latina: martedì e giovedì, ore 9.00-9.45  Roma: mercoledì, ore 10-12, Dip. Informatica e Sistemistica, via Salaria 113 II piano, 00198 Roma A. Drozdek, Algoritmi e strutture dati in Java, Apogeo Ingegneria 2000, via della polveriera 15 (S. Pietro in vincoli), tel. 06 4744169/06 4746609  Testi consigliati:  T. Cormen e altri. Introduzione agli algoritmi. Ed. Jackson libri  Altro materiale: documentazione su Java disponibile in rete 1 Informazioni generali/2  Java tutorial:     http://java.sun.com/docs/books/tutorial/ Il Java tutorial è parte di una più ampia documentazione disponibile al sito Sun API Java: la documentazione è disponibile al sito: http://java.sun.com/products/jdk/1.2/docs/api/in dex.html e può essere scaricata a partire da: http://java.sun.com/products/jdk/1.2/docs/ J. Bishop: Java gently – Corso introduttivo. Addison - Wesley P. Niemeyer e altri. Learning Java. O'REILLY  D. Flanagan. Java in a nutshell. O'REILLY 2 Obiettivi  A cosa serve la progettazione di algoritmi e strutture dati  Come si misura l’efficienza delle strutture dati e degli algoritmi  Come scegliere gli algoritmi e le strutture dati adatti a risolvere in modo efficiente un problema  Implementazione di algoritmi e strutture dati in Java 3 Argomenti del corso  Introduzione: efficienza e sua misura.  Riepilogo sulle principali strutture dati di base:     liste, code, pile, alberi Code di priorità Dizionari Aspetti avanzati degli algoritmi di ordinamento Grafi o Rappresentazione e algoritmi di visita o Algoritmo di Dijkstra per il calcolo del percorso minimo o Minimo albero ricoprente 4 Algoritmi e strutture dati Definizioni  Struttura dati: organizzazione sistematica dei dati e del loro accesso  Algoritmo: procedura suddivisa in passi che, eseguiti in sequenza, consentono di eseguire un compito in tempo finito  Esempio: Max. di un vettore di n elementi Algorithm arrayMax(A, n) currentMax = A[0]; for (i=0; i < n; i++) if (A[i] > currentMax) currentMax = A[i]; return currentMax; 5 Nel mondo reale.......  Gli algoritmi intervengono (in modo più o meno nascosto) in molti aspetti  Esempi      Internet DBMS Motori di ricerca Struttura del Web Analisi di documenti 6 Esempio: Routing in Internet Protocollo di Routing 5 Obiettivo: determinare “buon” cammino sorg.-dest. Astrazione usando grafi:  I nodi rappresentano router  Gli archi descrivono i link fisici  Costi sugli archi (link) : ritardo, costo in £, livello di congestione 2 A B 2 1 D 3 C 3 1 5 F 1 E 2  Cammino “buono”:  Di solito significa cammino a costo minimo  Possibili def. alternative 7 Esempio: Accesso a basi di dati Interrogazione Obiettivo: rispondere rapidamente. Interrogazione ... Data base Data Record 8 Qualità di algoritmi e strutture dati  Efficienza  Tempo di esecuzione  Spazio (quantità di memoria) I due aspetti sono interdipendenti 9 Come misurare l’efficienza? 10 ms Programma A Dati Problema Programma B 1 ms  Perché B gira più velocemente ?  Possiamo affermare che B sia “migliore” di A? 11 Misura dell’efficienza obiettivi  Indipendenza dall’implementazione  Generale (valida per ogni input, di qualsiasi dimensione)  Misura indipendente dalla piattaforma Hw/Sw 12 Modello di costo RAM Random Access Machine Macchina che esegue le istruzioni in sequenza. Insieme di operazioni primitive a costo unitario:  Assegnazione  A = 10; (costo 1)  Op. aritmetiche  A = B*C + D – 7; (costo 4)  Test  A == B (costo 1)  Lettura/Scrittura  System.out.println(A); (Costo 1) 13 Modello di costo/2 Costo di operazioni complesse:  Ciclo: somma costo test di fino ciclo e costo corpo del ciclo  if…then…else: costo test più costo blocco istruzioni che segue then o else (a seconda del caso)  Attivazione di un metodo: somma dei costi di tutte le istruzioni presenti nel metodo Costo: somma di tutti i costi 14 Esempio  Nel primo caso (vett. di 3 elementi) si ha costo 1 (ass.)+1 (ass. nel for) + 6 (test e incr. nel for) + 1 (test finale for) + 3 (test if) + 1 (istruz. return) = 13  Nel secondo caso si ha 1 (ass.) + 1 (ass. nel for) + 10 (test e incr. nel for) + 1 (test finale for) + 5 (test if) + 1 (istr. ass. nell’if) + 1 (istruz. return) = 20 AlgorithmarrayMax(A, n) currentMax=A[0]; for (i=0; i<n; i++) if (A[i]>currentMax) currentMax=A[i]; return currentMax; 1 8 7 6 1 3 4 4 n=3 n=5 15 Perché il modello è accettabile? MUL B,C ADD A,B A=A+B*C; B A C Ogni istruzione corrisponde a una sequenza finita di istruzioni macchina Ogni variabile occupa una quantità finita di memoria e quindi i tempi di accesso a due variabili sono legati da una costante N finito (es. 32 o 64 ) 16 Vantaggi e svantaggi  Vantaggi: prescinde dalla piattaforma Hw/Sw e dal linguaggio di programmazione  Svantaggi: l’indicazione che si ottiene è qualitativa 17 Quale input considerare?  La misura deve dipendere dalla dimensione dell’input (n nel nostro esempio) ma non dal particolare input considerato  Possibile alternative:  Analisi del caso peggiore: si considera il costo di esecuzione nel caso peggiore  Analisi del caso medio: si considera il costo medio dell’algoritmo rispetto ad una distribuzione dell’input (richiede la conoscenza della distribuzione)  In ogni caso occorre definire la dimensione dell’input 18 Dimensione dell’input  In generale: No. bit necessari a rappresentare l’input  Esempio (calcolo del Max. in un array di n interi)  n interi finiti (< MAXINT)  log(MAXINT) bit per rappresentare ogni valore.  Poiché MAXINT è una costante in pratica, il numero di bit necessari a rappresentare un intero è costante (es. 32)  Quindi: dimensione input è proporzionale a n  A volte le cose possono non essere così ovvie (si pensi al problema di indovinare un numero proposto nell’ultima slide) 19 Analisi nel caso peggiore (esempio)  Nel caso peggiore l’elemento massimo è l’ultimo  In questa ipotesi l’istruzione currentMax=A[i]; è eseguita n-1 volte.  Il costo complessivo dell’algoritmo è allora 1+1+(n1)+1+2(n-1)+1=4n+1 AlgorithmarrayMax(A, n) currentMax=A[0]; for (i=0; i<n; i++) if (A[i]>currentMax) currentMax=A[i]; return currentMax; 1 4 6 3 8 20 Analisi asintotica  Se si considerano tutte le costanti l’analisi può divenire eccessivamente complessa  Interessa conoscere il costo al variare della dimensione dell’input, a meno di costanti  Motivo: il costo è comunque calcolato a meno di costanti, per le ipotesi fatte circa il modello  Un’analisi di questo tipo è detta asintotica  L’analisi asintotica è influenzata dall’operazione dominante di un algoritmo 21 Analisi asintotica/2  f(n), g(n) funzioni dagli interi ai reali  f(n)=O(g(n)) se esiste c>0 reale, e una costante intera n0  1 tali che, per ogni che f (n)  cg (n) per ogni n  n0   f (n)  ( g (n)) se esiste c>0 reale, e una costante intera n0  1 tali che, per ogni che f (n)  cg (n) per ogni n  n0 f (n)  ( g (n)) se f(n)=O(g(n)) e f (n)  ( g (n))  f(n)=o(g(n)) se, per ogni c>0, esiste n0>0 tale che f (n)  cg (n) per ogni n  n0 (attenzione alle differenze!!)  f (n)   ( g (n)) se g(n)=o(f(n))  In base a tali definizioni, l’algoritmo AlgorithmarrayMax ha costo O(n) 22 Istruzione dominante  Un’ operazione o istruzione si dice dominante se il numero d(n) di volte che essa è eseguita nel caso peggiore di input di dimensione n soddisfa: f(n)<=a d(n) + b, dove f(n) è la complessità dell’algoritmo nel caso peggiore ed a e b sono costanti opportune  Es.: istruzione if (A[i]>currentMax) in AlgorithmarrayMax(A, n) 23 Esempi  In base a tali definizioni, l’algoritmo AlgorithmarrayMax ha costo (n)  f(n)= 3n2+10 n = O(n2) Per c=4 e n0>=10, 3n2+10 n <= 4 n2 1 2  f (n)  n  3n  (n 2 ) 2 Per c1= 1/14, c2= 1/2, n0>=7, 1 2 c1n  n  3n  c2 n 2 2 2 24 Analisi asintotica/3 Limiti dell’approccio:  Le costanti nascoste possono essere molto grandi: un algoritmo con costo 1050n è lineare ma potrebbe essere poco pratico  Comportamento nel caso di istanze “piccole” (es. 3n contro n2)  Il caso peggiore potrebbe verificarsi raramente 25 Analisi di Insertion Sort Algorithm insertionSort(A, n) for (i=0; i<n; i++) { tmp=A[i]; for (j=i; j>0 && tmp<A[j-1]; j--) A[j]=A[j-1]; A[j] = tmp; } return A; Inserisce l’elemento A[i] nella posizione corretta nel vettore ordinato A[0,…,i-1] Ex: 54321 i=0 i=1 i=2 i=3 i=4 54321 45321 34521 23451 12345 0 confronti 1 confronto 2 confronti 3 confronti 4 confronti n(n  1) f ( n)  i  O(n 2 ) i 0 2 n 1 Ex: 12345 f(n)= n 26 Esempi class esercizio { public void Ex1(int n) { int a, i; for (i=0; i<n;i++) a=i; } public void Ex2(int n) { int a, i; for (i=0; i<n*n;i++) a=i; } public void Ex3(int n) { int a, i, j; for (i=0; i<n;i++) for (j=0; j<=i;j++) a=i; } } Valutare la complessità dei tre metodi Complessità di Ex3: 1+2+....+n=O(n2) 27 Metodo Divide et Impera  Il problema è risolto ricorsivamente attraverso la sua scomposizione in problemi di taglia inferiore  Divide: Problema suddiviso in un numero di sottoproblemi di taglia inferiore Impera: Sottoproblemi risolti ricorsivamente o direttamente se di dimensione piccola a sufficienza Combina: Le soluzioni dei sottoproblemi sono combinate per ottenere la soluzione al problema originale 29 Merge Sort A[0...n] A[0...n/2-1] A[n/2...n-1] Suddividi A in due sottovettori di dim. n/2 A[0...n/2-1] A[n/2...n-1] MergeSort A[0...n/2-1] Si suppone n pari per semplicità MergeSort A[n/2...n-1] Merge A ordinato 30 Merge Sort/2 void mergesort(int[] A, int first, int last) { if (first < last) { int mid = (first + last) / 2; mergesort(A, first, mid); mergesort(A, mid+1, last); merge(A, first, last); } } 31 Merge Sort A[0...n] /3  Divide: divide gli n elementi da ordinare in due sottosequenze da n/2 elementi. Costo: O(n) Impera: ordina ricorsivamente usando il merge sort le due sottosequenze. Costo: 2f(n/2) Combina: fonde le due sottosequenze ordinate. Costo: O(n)  La ricorsione termina quando si hanno solo due elementi da ordinare. Costo:O(1)  Costo dell’algoritmo Merge Sort:  (1), n  2 f ( n)    2 f (n / 2)   ( n), n  2 32 L’array [1 8 6 4 10 5 3 2 22] ordinato con mergesort 33 Merge void merge(int[] data, int first, int last) { int mid = (first + last) / 2; int i1 = 0, i2 = first, i3 = mid + 1; while (i2 <= mid && i3 <= last) if (data[i2] <data[i3]) temp[i1++] = data[i2++]; else temp[i1++] = data[i3++]; while (i2 <= mid) temp[i1++] = data[i2++]; while (i3 <= last) temp[i1++] = data[i3++]; for (i1 = 0, i2 = first; i2 <= last; data[i2++] = temp[i1++]); } 34 Equazioni di ricorrenza  Tempo di esecuzione di algoritmi ricorsivi descritti con equazioni di ricorrenza. Ex: MergeSort: c1 , n  1  f ( n)   2 f (n / 2)  c2 n, n  2  Semplificazioni:  Argomenti non interi.  (1), n  2 f ( n)    f ( n / 2)  f ( n / 2)   (n), n  2  Condizioni al contorno:  (1) per n piccolo 35 Soluzione di equazioni di ricorrenza  Metodo per sostituzione. Si tenta una soluzione e si verifica se soddisfa l’equazione di ricorsione.  Ex: Merge Sort: f (n)  cn log n  a, a  c1 , c  c2 f (n)  2c(n / 2) log( n / 2)  c2 n  a  cn log( n / 2)  c2 n  a  cn log n  cn  c2 n  a  cn log n  a f (1)  c1  cn log n  a  a 36 Esercizi  Mostrare che la soluzione di f(n)=f(n/2)+1 è O(log n)  Mostrare che la soluzione di f(n)=2f((n/2)+17)+n è O(n log n) 37 Esercizi/2  Si consideri il problema della ricerca in un vettore di interi: dato il vettore A[1..n] ed un intero k, si vuole stabilire se k sia tra gli elementi di A o meno  Considerato il classico algoritmo basato sulla ricerca binaria, si mostri che esso ha complessità O(log n) 38 Esercizi/3  Si consideri il problema di “indovinare” un numero intero nel numero minimo di tentativi: ad ogni tentativo, l’algoritmo propone un valore ad un oracolo, che conosce il numero da indovinare. L’oracolo risponde dicendo se il numero proposto sia maggiore, minore o uguale a quello da indovinare (nell’ ultimo caso il gioco termina).  Si proponga un algoritmo efficiente e se ne esprima la complessità temporale in funzione del generico numero N da indovinare 39