Didattica dei Fondamenti dell’Informatica 2 Seconda giornata: progettare un algoritmo corretto, efficiente, e possibilmente ottimo! Guido Proietti Email:

Slides:



Advertisements
Presentazioni simili
Algoritmi e Strutture Dati
Advertisements

Problema dellordinamento Input: Sequenza di n numeri Output: Permutazione π = tale che: a 1 a 2 …… a n Subroutine in molti problemi E possibile effettuare.
Algoritmi e Strutture Dati
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
                      Insertion-Sort
Alberi binari di ricerca
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Stesso approccio.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Ordinamenti ottimi.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie di analisi.
Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie di analisi.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Ordinamenti lineari.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
Capitolo 4 Ordinamento Algoritmi e Strutture Dati Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano.
Capitolo 3 Strutture dati elementari Algoritmi e Strutture Dati.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Stesso approccio.
Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie di analisi.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Usa la tecnica del.
Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie di analisi.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Stesso approccio.
Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie di analisi.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
Algoritmi e strutture Dati - Lezione 7
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
Il problema del dizionario
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Capitolo 1 Unintroduzione.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Capitolo 4 Ordinamento: Heapsort Algoritmi e Strutture Dati.
Il problema della ricerca Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Capitolo 9 Il problema della gestione di insiemi disgiunti (Union-find) Algoritmi e Strutture Dati.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Usa la tecnica del.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati (Mod. A)
Algoritmi e Strutture Dati III. Algoritmi di Ordinamento
Algoritmi di ordinamento
Heap binari e HeapSort.
Heap binomiali Gli heap binomiali sono strutture dati su cui si possono eseguire efficientemente le operazioni: Make(H) : crea uno heap vuoto Insert(H,
QuickSort Quick-Sort(A,s,d) IF s < d THEN q = Partiziona(A,s,d) Quick-Sort(A,s,q-1) Quick-Sort(A,q + 1,d)
Elementi di Informatica di base
Algoritmi e Strutture Dati
La complessità media O(n log n) di Quick-Sort vale soltanto se tutte le permutazioni dell’array in ingresso sono ugualmente probabili. In molte applicazioni.
Teoria degli algoritmi e della computabilità Terza giornata: Ricerca e ordinamento ottimi. P vs NP, algoritmi di approssimazione, e il potere della randomizzazione.
Teoria degli algoritmi e della computabilità Seconda giornata: progettare un algoritmo corretto, efficiente, e possibilmente ottimo! Guido Proietti
Algoritmi e Strutture Dati Luciano Gualà
GLI ALGORITMI VISIBILE SUL BLOG INFORMATICA ANNO SCOLASTICO 2013 / 2014 GABRIELE SCARICA 2°T.
Didattica e Fondamenti degli Algoritmi e della Calcolabilità Quarta giornata Risolvere efficientemente un problema in P: la sequenza di Fibonacci Guido.
Didattica e Fondamenti degli Algoritmi e della Calcolabilità Terza giornata: principali classi di complessità computazionale dei problemi Guido Proietti.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
1 Ordinamento (Sorting) INPUT: Sequenza di n numeri OUTPUT: Permutazione π = tale che a 1 ’  a 2 ’  … …  a n ’ Continuiamo a discutere il problema dell’ordinamento:
Algoritmi e strutture Dati - Lezione 7 1 Algoritmi di ordinamento ottimali L’algoritmo Merge-Sort ha complessità O(n log(n))  Algoritmo di ordinamento.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl Capitolo 4 Ordinamento:
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie.
1 Ordinamento (Sorting) Input: Sequenza di n numeri Output: Permutazione π = tale che: a i 1  a i 2  ……  a i n Continuiamo a discutere il problema dell’ordinamento:
Didattica e Fondamenti degli Algoritmi e della Calcolabilità Quinta giornata Risolvere efficientemente un problema in P: ancora sulla sequenza di Fibonacci.
Didattica e Fondamenti degli Algoritmi e della Calcolabilità Sesta giornata Risolvere efficientemente un problema in P: Il problema dell’ordinamento: Insertion.
GLI ALGORITMI DI ORDINAMENTO
Capitolo 4 Ordinamento: lower bound Ω(n log n) e MergeSort ((*) l’intera lezione) Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati HeapSort. Select Sort: intuizioni L’algoritmo Select-Sort  scandisce tutti gli elementi dell’array a partire dall’ultimo elemento.
Transcript della presentazione:

Didattica dei Fondamenti dell’Informatica 2 Seconda giornata: progettare un algoritmo corretto, efficiente, e possibilmente ottimo! Guido Proietti Email: guido.proietti@univaq.it URL: www.di.univaq.it/~proietti/index_personal

Richiamo: Complessità computazionale di un algoritmo e di un problema Definizione Un algoritmo A ha una complessità computazionale O(f(n)) su istanze di dimensione n se T(n)=O(f(n)), ove T(n) è il numero di passi elementari dell’algoritmo sulle istanze di ingresso di dimensione n che comportano più lavoro per l’algoritmo stesso (ovvero, T(n) misura il caso peggiore dell’algoritmo) Definizione Un problema P ha una complessità computazionale O(f(n)) se esiste un algoritmo che risolve P la cui complessità computazionale è O(f(n))

Richiamo: gerarchia delle classi Decidibili ExpTime (ARRESTO(k)) P (ricerca) NP NP-completi (SAT)

Progettare un algoritmo Vogliamo progettare algoritmi (per problemi calcolabili!) che: Producano correttamente il risultato desiderato Siano efficienti in termini di tempo di esecuzione ed occupazione di memoria

Le quattro proprietà fondamentali di un algoritmo (oltre l’efficienza) La sequenza di istruzioni deve essere finita Essa deve portare ad un risultato corretto Le istruzioni devono essere eseguibili materialmente Le istruzioni non devono essere ambigue

Algoritmi e strutture dati Concetto di algoritmo è inscindibile da quello di dato Da un punto di vista computazionale, un algoritmo è una procedura che prende dei dati in input e, dopo averli elaborati, restituisce dei dati in output  I dati devo essere organizzati e strutturati in modo tale che la procedura che li elabora sia “efficiente”

Analisi di algoritmi Correttezza: dimostrare formalmente che un algoritmo è corretto Complessità: Stimare la quantità di risorse (tempo e memoria) necessarie all’algoritmo stimare il più grande input gestibile in tempi ragionevoli confrontare due algoritmi diversi ottimizzare le parti “critiche”

Notazione asintotica W f(n) = W(g(n)) se  due costanti c>0 e n0≥0 tali che f(n) ≥ c g(n) per ogni n ≥ n0 n0 n f(n) = W( g(n) ) f(n) c g(n)

Esempi Sia f(n) = 2n2 - 5n; vogliamo dimostrare che f(n)= W(n2). f(n)/n2 = (2n2 - 5n)/n2 = 2 - 5/n ma 2 - 5/n ≥ 1 per n ≥ 5 quindi basta scegliere c=1 e n0=5 e avremo che 2n2 - 5n ≥ 1n2 per n ≥ n0=5. f(n) = W(n) (c=1, n0=2) f(n) = W(log n) (c=1, n0=2) Invece, f(n)  (n3)

Legame con il concetto di limite

Notazione asintotica Q f(n) = Q(g(n)) se  tre costanti c1,c2>0 e n0≥0 tali che c1 g(n) ≤ f(n) ≤ c2 g(n) per ogni n ≥ n0 n0 n f(n) = Q( g(n) ) f(n) c1 g(n) c2 g(n)

Relazioni tra O, Ω e Θ

Caso migliore di un algoritmo Sia tempo(I) il tempo di esecuzione di un algoritmo sull’istanza I Tbest(n) = min istanze I di dimensione n {tempo(I)} Intuitivamente, Tbest(n) è il tempo di esecuzione sulle istanze di ingresso che comportano meno lavoro per l’algoritmo

Caso medio di un algoritmo Sia P(I) la probabilità di occorrenza del- l’istanza I Tavg(n) = ∑ istanze I di dimensione n {P(I) tempo(I) } Intuitivamente, Tavg(n) è il tempo di esecuzione nel caso medio, ovvero sulle istanze di ingresso “tipiche” per il problema Richiede di conoscere una distribuzione di probabilità sulle istanze

IL problema: l’ordinamento Dato un insieme S di n elementi presi da un dominio totalmente ordinato, ordinare S Esempi: ordinare una lista di nomi alfabeticamente, o un insieme di numeri, o un insieme di compiti d’esame in base al cognome dello studente Subroutine in molti problemi È possibile effettuare ricerche in array ordinati in tempo O(log n) (ricerca binaria)

Il problema dell’ordinamento (non decrescente) Input: una sequenza di n numeri (reali) <a1,a2,…,an> (NOTA: la dimensione dell’input è n) Output: una permutazione {1,2,…,n}  {i1,i2,…,in}, ovvero un riarrangiamento <ai1, ai2,…, ain> della sequenza di input in modo tale che ai1  ai2 … ain

SelectionSort Approccio incrementale: assumendo che i primi k elementi siano ordinati, estende l’ordinamento ai primi k+1 elementi scegliendo il minimo degli n-k elementi non ancora ordinati e mettendolo in posizione k+1

NOTA: Assumiamo che il primo elemento dell’array sia in A[1] SelectionSort (A) for k=1 to n-1 do m = k for j=k+1 to n do if (A[j] < A[m]) then m=j scambia A[m] con A[k] NOTA: Assumiamo che il primo elemento dell’array sia in A[1] linea 2: m mantiene l’indice dell’array in cui si trova il minimo corrente linee 3-4: ricerca del minimo fra gli elementi A[k],…,A[n] (m viene aggiornato con l’indice dell’array in cui si trova il minimo corrente) linea 5: il minimo è spostato in posizione k

Correttezza Si dimostra facendo vedere che alla fine del generico passo k (k=1,…, n-1) si ha: (i) i primi k elementi sono ordinati e (ii) contengono i k elementi più piccoli dell’array Induzione su k: k=1: Alla prima iterazione viene semplicemente selezionato l’elemento minimo dell’array  (i) e (ii) banalmente verificate. k>1. All’inizio del passo k i primi k-1 elementi sono ordinati e sono i k-1 elementi più piccoli nell’array (ipotesi induttiva). Allora la tesi segue dal fatto che l’algoritmo seleziona il minimo dai restanti n-k elementi e lo mette in posizione k. Infatti: (ii) i primi k elementi restano i minimi nell’array (i) l’elemento in posizione k non è mai più piccolo dei primi k-1 elementi

Complessità temporale SelectionSort (A) for k=1 to n-1 do m = k for j=k+1 to n do if (A[j] < A[m]) then m=j scambia A[m] con A[k] 1 assegnamento n-k confronti (operaz. dominante) il tutto eseguito per k=1,…, n-1 1 scambio (3 assegnamenti) n-1 n-1 T(n) =  [1+(n-k)+1]=2(n-1)+ k =2(n-1)+n·(n-1)/2 = (n2) k=1 k=1 Si noti che T(n) è PROPRIO UGUALE ad un polinomio di 2º grado in n, e quindi la notazione Θ è perfettamente ESPRESSIVA del valore di T(n) T(n) = Tbest(n) = Tavg(n) = (n2)

InsertionSort Approccio incrementale: assumendo che i primi k elementi siano ordinati, estende l’ordinamento ai primi k+1 elementi, inserendo l’elemento in posizione k+1-esima nella giusta posizione rispetto ai primi k elementi

Linea 2: elemento x=A[k+1] da inserire nella posizione che gli compete InsertionSort (A) for k=1 to n-1 do x = A[k+1] for j=1 to k+1 do if (A[j] > x) then break if (j < k+1) then for t=k downto j do A[t+1]= A[t] A[j]=x Linea 2: elemento x=A[k+1] da inserire nella posizione che gli compete Linee 3 e 4: individuano la posizione j in cui va messo x Linee 5 e 6: se la posizione j è diversa da k+1, si fa spazio per inserire x, “shiftando” tutti gli elementi da j a k verso destra

Correttezza Si dimostra facendo vedere che alla fine del generico passo k (k=1,…, n-1) i primi k+1 elementi sono ordinati (si noti la differenza con il Selection Sort, in cui invece dovevamo far vedere anche che erano i più piccoli) Induzione su k: k=1: banale: si riordinano A[1] e A[2]; k>1: All’inizio del passo k i primi k elementi sono ordinati (ipotesi induttiva). Allora la tesi segue dal fatto che l’algoritmo inserisce A[k+1] nella giusta posizione rispetto alla sequenza A[1],…,A[k]

Complessità temporale InsertionSort (A) for k=1 to n-1 do x = A[k+1] for j=1 to k+1 do if (A[j] > x) then break if (j < k+1) then for t=k downto j do A[t+1]= A[t] A[j]=x 1 assegnamento il tutto eseguito per k=1,…, n-1 j*≤k+1 confronti k+1 oper. k+1–j* assegnamenti n-1 T(n) = (n)+ (k+1) =  (n2) k=1 T(n) = Tbest(n) = Tavg(n) = (n2) Possiamo fare meglio?

Una variante dell’IS più efficiente InsertionSort2 (A) for k=1 to n-1 do x = A[k+1] j = k while j > 0 e A[j] > x do A[j+1] = A[j] j= j-1 A[j+1]=x il tutto eseguito per k=1,…, n-1 tk ≤ 2k assegnam. n-1 n-1 tempo(n)=(n)+ tk ≤ (n)+ 2k = (n)+n·(n-1) = (n2)  tempo(n) = O(n2) k=1 k=1 Si noti che tempo(n) è AL PIÙ UGUALE ad un polinomio di 2º grado in n, e quindi la notazione O è perfettamente ESPRESSIVA del valore di T(n)

Caso migliore, peggiore, e medio di InsertionSort2 array già ordinato in ordine crescente  tk = 0  Tbest(n) = (n) (costo del ciclo for esterno) Caso peggiore array ordinato in ordine decrescente  tk = 2k  T(n) =  2k = (n2) Caso medio L’elemento in posizione k+1 ha la medesima probabilità di essere inserito in ciascuna delle k posizioni che lo precedono  la sua posizione attesa è k/2  il valore atteso di tk = k  Tavg(n) =  k = (n2)  n-1 k=1 n-1 k=1

« Se qualcosa può andar male, lo farà. » Legge di Murphy? « Se qualcosa può andar male, lo farà. » In realtà, negli algoritmi il caso medio costa spesso come il caso peggiore (asintoticamente), in quanto le strutture di controllo fondamentali degli algoritmi sono i cicli, e spesso il caso medio implica l’esecuzione della metà delle istruzioni di un ciclo, senza quindi avere un abbattimento asintotico della complessità.

Riepilogo Caso migliore Caso medio Caso peggiore Selection Sort Θ(n2) Insertion Sort 1 Θ(n2) Θ(n2) Θ(n2) Insertion Sort 2 Θ(n) Θ(n2) Θ(n2)

Complessità spaziale Ricordiamo che oltre alla complessità temporale dobbiamo valutare anche la complessità spaziale di un algoritmo, ovvero lo spazio di memoria necessario per ospitare le strutture di dati utilizzate dall’algoritmo. La complessità spaziale del Selection Sort e dell’Insertion Sort è Θ(n) Nota: Se la complessità spaziale di un certo algoritmo è Θ(g(n)), e se tale algoritmo “ispeziona” l’intera memoria occupata, allora la complessità temporale dell’algoritmo è (g(n)), ovviamente.

Conseguenze per il problema dell’ordinamento La complessità spaziale di qualsiasi algoritmo che risolve il problema dell’ordinamento è (n) (dimensione input) …ma qualsiasi algoritmo che risolve il problema dell’ordinamento deve ispezionare tutti i dati in ingresso, e quindi ha complessità temporale T(n)=(n)  Tutti gli algoritmi che risolveranno il problema dell’ordinamento avranno una complessità temporale (n)

Delimitazioni inferiori (lower bound) Definizione Un algoritmo A ha complessità computazionale (g(n)) su istanze di dimensione n se T(n)=(g(n)) (significa che numero di passi elementari necessari per eseguire A nel caso peggiore è (g(n)), e quindi non è detto che debbano essere necessari per ogni istanza di dimensione n: istanze facili potrebbero richiedere meno risorse!) Definizione (lower bound o complessità intrinseca di un problema) Un problema P ha una delimitazione inferiore alla complessità computazionale (g(n)) se ogni algoritmo che risolve P ha complessità computazionale (g(n)).

Ottimalità di un algoritmo Definizione Dato un problema P con complessità intrinseca (g(n)), un algoritmo che risolve P è ottimo (in termini di complessità asintotica, ovvero a meno di costanti moltiplicative e di termini additivi/sottrattivi di “magnitudine” inferiore) se ha complessità computazionale O(g(n)).

Quindi, per il problema dell’ordinamento… Upper bound temporale: O(n2) Insertion Sort, Selection Sort Lower bound temporale: (n) “banale”: dimensione dell’input Abbiamo un gap lineare tra upper bound e lower bound! Possiamo fare meglio, ovvero abbassare l’upper bound e/o innalzare il lower bound ?

Ordinamento per confronti Dati due elementi ai ed aj, per determinarne l’ordinamento relativo effettuiamo una delle seguenti operazioni di confronto: ai  aj ; ai  aj ; ai  aj ; ai  aj ; ai  aj Non si possono esaminare i valori degli elementi o ottenere informazioni sul loro ordine in altro modo. Notare: Tutti gli algoritmi di ordinamento considerati fino ad ora sono algoritmi di ordinamento per confronto.

Lower bound W(n log n) per l’ordinamento Consideriamo un generico algoritmo A, che ordina eseguendo solo confronti: dimostreremo che A esegue (nel caso peggiore) W(n log n) confronti Un generico algoritmo di ordinamento per confronti lavora nel modo seguente: Confronta due elementi ai ed aj (ad esempio effettua il test ai  aj); A seconda del risultato, riordina e/o decide il confronto successivo da eseguire.  Un algoritmo di ordinamento per confronti può essere descritto in modo astratto usando un albero di decisione, nel quale i nodi interni rappresentano i confronti, mentre le foglie rappresentano gli output prodotti

Albero di decisione Descrive le diverse sequenze di confronti che A esegue su un’istanza <a1,a2,…,an> di lunghezza n; i movimenti dei dati e tutti gli altri aspetti dell’algoritmo vengono ignorati Nodo interno (non foglia): i:j (modella il confronto tra ai e aj) Nodo foglia: i1,i2,…,in (modella una risposta (output) dell’algoritmo, ovvero una permutazione <ai1,ai2,…,ain> degli elementi) L’albero di decisione è associato ad un algoritmo e alla dimensione n dell’istanza

Esempio È proprio l’Insertion Sort 2! Input <a1,a2,a3> Riconoscete l’algoritmo associato?      È proprio l’Insertion Sort 2! Esercizio per casa: costruire l’albero di decisione per il SS su una sequenza di 3 elementi.

Proprietà Per una particolare istanza, i confronti eseguiti da A su quella istanza rappresentano un cammino radice – foglia L’algoritmo segue un cammino diverso a seconda delle caratteristiche dell’input Caso peggiore: cammino più lungo Caso migliore: cammino più breve Il numero di confronti nel caso peggiore è pari all’altezza dell’albero di decisione (ovvero alla lunghezza, in termini di numero di archi, del più lungo cammino radice-foglia)

h(k) ≥1+h(k/2) ≥ (hp induttiva) 1+log2(k/2) Altezza in funzione delle foglie Lemma: Un albero strettamente binario (ovvero, in cui ogni nodo interno ha esattamente due figli) con k foglie ha altezza h(k)  log2 k. Dim: Dimostrazione per induzione su k: Caso base k=1 (albero-nodo ): banale h(k)=0≥ log21=0 Caso k>1: supposto vero per k-1 foglie, dimostriamolo per k; poiché la radice ha 2 figli, uno dei due suoi sottoalberi deve contenere almeno la metà (parte intera sup.) delle foglie, e quindi h(k) ≥1+h(k/2) ≥ (hp induttiva) 1+log2(k/2) =1+log2k-log22=log2k. QED

Il lower bound W(n log n) Consideriamo l’albero di decisione di un qualsiasi algoritmo che risolve il problema dell’ordinamento di n elementi Tale albero deve avere almeno n! foglie: infatti, se l’algoritmo è corretto, deve contemplare tutti i possibili output, ovvero le n! permutazioni della sequenza di n elementi in input Dal lemma precedente, avremo che l’altezza h(n) dell’albero di decisione sarà: h(n)  log2(#foglie)  log2(n!) > log2 (n/e)n = = n log2 (n/e) = Formula di Stirling: n!  (2pn)1/2 ·(n/e)n > (n/e)n = n log2 n – n log2 e = = W(n log n) QED

Un algoritmo ottimo: il MergeSort (John von Neumann, 1945) Problema dell’ordinamento: Lower bound - (n log n) albero di decisione Upper bound – O(n2) IS,SS Proviamo a costruire un algoritmo ottimo, usando la tecnica del divide et impera: Divide: dividi l’array a metà Risolvi il sottoproblema ricorsivamente Impera: fondi le due sottosequenze ordinate

Esempio di esecuzione Input ed output delle chiamate ricorsive

Fusione di sequenze ordinate Due array ordinati A e B possono essere fusi rapidamente: estrai ripetutamente il minimo di A e B e copialo nell’array di output, finché A oppure B non diventa vuoto copia gli elementi dell’array non ancora completamente svuotato alla fine dell’array di output Notazione: dato un array A e due indici x  y, denotiamo con A[x;y] la porzione di A costituita da A[x], A[x+1],…,A[y]

Osservazione: usa l’array ausiliario X Algoritmo di fusione di sequenze ordinate Merge (A, i1, f1, f2) Sia X un array ausiliario di lunghezza f2-i1+1 i=1 i2=f1+1 while (i1 f1 e i2  f2) do if (A[i1]  A[i2]) then X[i]=A[i1] incrementa i e i1 else X[i]=A[i2] incrementa i e i2 if (i1<f1) then copia A[i1;f1] alla fine di X else copia A[i2;f2] alla fine di X copia X in A[i1;f2] fonde A[i1;f1] e A[f1+1;f2] output in A[i1;f2] Osservazione: usa l’array ausiliario X

Costo dell’algoritmo di merge Lemma La procedure Merge fonde due sequenze ordinate di lunghezza n1 e n2 eseguendo al più n1+ n2 -1 confronti Dim: Ogni confronto “consuma” un elemento di A. Nel caso peggiore tutti gli elementi tranne l’ultimo sono aggiunti alla sequenza X tramite un confronto. Il numero totale di elementi è n1+ n2. Quindi il numero totale di confronti è n1+ n2 -1. QED Numero di confronti: C(n=n1+ n2)=O(n1+ n2)=O(n) (si noti che vale anche C(n)=Ω(min{n1,n2})) Numero di operazioni (confronti + copie)? T(n)=(n1+ n2)

MergeSort MergeSort (A, i, f) if (i  f) then return m = (i+f)/2 MergeSort(A,i,m) MergeSort(A,m+1,f) Merge(A,i,m,f)

Complessità del MergeSort Si vede facilmente che il tempo di esecuzione di MergeSort è: T(n) = 2 T(n/2) + Θ(n) con T(1)=1, da cui: T(n)=2(2T(n/22)+Θ(n/2))+Θ(n)= =2(2(2T(n/23)+Θ(n/22))+Θ(n/2))+Θ(n)=… e per k = log2n si ha n/2k = 1 e quindi T(n)=2(2(…(2T(n/2k)+Θ(1))+…+Θ(n/22))+Θ(n/2))+Θ(n) = 2log n·Θ(1)+2log n-1·Θ(2)+2log n-2·Θ(22)+…+ 20·Θ(n) = n∙Θ(1)+n/2∙Θ(2)+n/4∙Θ(4)+…+1∙Θ(n) = Θ(n log n)

Più precisamente… Nel caso peggiore, il MS esegue (n ⌈log n⌉ - 2⌈log n⌉ + 1) confronti, che corrisponde ad un numero compreso tra (n log n - n + 1) e (n log n + n + O(log n)) Nel caso medio, il MS esegue (n ⌈log n⌉ - 2⌈log n⌉ + 1) – 0.2645·n confronti Nel caso migliore (array già ordinato), il MS esegue n-1 confronti

Osservazioni finali Il MergeSort è un algoritmo (asintoticamente) ottimo rispetto al numero di confronti eseguiti nel caso peggiore Il MergeSort non ordina in loco, e utilizza memoria ausiliaria (l’occupazione di memoria finale è pari a 2n)