Divide et impera. Divide et impera. Divide et impera. Divide et impera

Dimensione: px
Iniziare la visualizzazioe della pagina:

Download "Divide et impera. Divide et impera. Divide et impera. Divide et impera"

Transcript

1 Divide et impera Divide et impera La tecnica detta divide et impera è una strategia generale per impostare algoritmi (par. 9.4). Consideriamo un problema P e sia n la dimensione dei dati, la strategia consiste nel: suddividere il problema in k sottoproblemi P i di dimensione inferiore (ciascuno di dimensione n i ) e successivamente riunire i risultati ottenuti dalle k soluzioni. La frase è attribuita a Filippo il Macedone e fu un principio politico: mantenere divise le popolazioni dominate per poter governare con più facilità. Divide et impera Se i k sottoproblemi sono formalmente simili al problema di partenza, si ottiene una scomposizione ricorsiva. Ci deve pertanto essere una dimensione h del problema che porti ad una risoluzione diretta, vale a dire che non necessiti della ricorsione. Indichiamo con: S l insieme dei dati k il numero dei sottoproblemi h la dimensione limite Si può scrivere uno schema generale per la scomposizione. Divide et impera algoritmo DIVETIMP (S, n) se n < h allora risolvere direttamente il problema P altrimenti dividere S in k sottoinsiemi risolvere separatamente i k sottoproblemi P 1,, P k : DIVETIMP(S 1,n 1 ),, DIVETIMP(S k,n k ) riunire i risultati ottenuti //finese //fine algoritmo 1

2 Divide et impera: complessità Indichiamo con T(n) la complessità del problema P sull insieme dei dati di dimensione n; poiché l algoritmo è ricorsivo si ottengono delle formule di ricorrenza : T(n) = costante n<h T(n) = D(n) + C(n) + T(n 1 ) + T(n 2 ) + T(n k ) Ordinamenti quicksort e mergesort D(n): complessità dell algoritmo per dividere l insieme C(n): complessità dell algoritmo per riunire i risultati T(n i ): complessità dell algoritmo sull insieme di dimensione n i. L idea è la seguente: è più conveniente ordinare due array di s e t componenti piuttosto che un array di n componenti (s + t = n) si aumenta l efficienza dell ordinamento scambiando elementi lontani tra loro. (par. 9.4) Verifichiamo la prima idea. Supponiamo s=t=n/2 e prendiamo la formula n(n-1)/2 che rappresenta la complessità dell ordinamento nel caso peggiore e riscriviamola per n/2 invece che n: 2 [(n/2) (n/2 1) /2] = n 2 /4 n/2 Confrontiamo le formule: n 2 /4 n/2 < n 2 /2 n/2 = (n 2 n)/2 = = n (n-1) /2 2

3 Verifichiamo la seconda idea. Supponiamo di avere un array ordinato in senso inverso; scambiando gli elementi opposti (il primo con l ultimo, il secondo con il penultimo, ecc.) in n/2 operazioni ordiniamo l array. Questi elementi sono lontani tra loro: quelli più grandi sono al posto di quelli più piccoli. Esempio. a = (10, 8, 7, 5, 4, 2, 0, -1) (-1, 0,....., 8, 10) Dividiamo l insieme in due parti e scambiamo elementi lontani. Scegliamo un elemento dell array per eseguire i confronti e lo chiamiamo conf; dividiamo l insieme in modo tale che gli elementi più piccoli di conf possano essere messi a sinistra di conf e quelli più grandi a destra, rispettando così l ordine. A questo punto l insieme è diviso in due parti indipendenti e l elemento conf è al suo posto. conf Si potrà proseguire in maniera ricorsiva fino a considerare un array di dimensione 1, che non dovrà essere ulteriormente suddiviso. Se guardiamo l array dalla prima componente all ultima (riunire i risultati), vediamo che l array è ordinato. Scriviamo il progetto dell algoritmo secondo lo schema divide et impera per ordinare un array v dalla componente n1 alla componente n2; alla prima chiamata, n1 ed n2 saranno la prima e ultima componente dell array. algoritmo quicksort(n1,n2,v) se n1 < n2 allora //finese //fine quicksort chiamare l algoritmo partizione(n1, n2, v, k) dove k è il valore della posizione di conf chiamare quicksort(n1, k-1, v) chiamare quicksort(k+1, n2, v) Quando n1=n2 l array ha un solo elemento e pertanto la ricorsione ha termine. 3

4 Come scegliere l elemento conf? Dobbiamo stabilire un criterio che si possa facilmente ripetere in tutte le suddivisioni successive. Stabiliamo di scegliere la prima componente di quella porzione di array (da n1 a n2) che vogliamo ordinare: v[n1]. Ci sono varie scritture dell algoritmo quicksort, alcune ottimizzano il numero di confronti, ma lasciano inalterata la complessità. Per realizzare la partizione avremo bisogno di due indici: un indice i che scorre l array con valori crescenti e che parte dalla posizione successiva a quella di conf (i=n1+1), un altro indice k che descrive l array con valori decrescenti e parte dall ultima posizione (k=n2). Quando questi due indici saranno uguali avremo terminato la partizione e si potrà sistemare conf al suo posto. Vediamo un progetto per l algoritmo di partizione. algoritmo partizione(n1, n2, v) conf v[n1] i n1+1 k n2 mentre i k eseguire mentre v[i] conf e i k eseguire i i+1 //fine mentre mentre v[k] conf e i k eseguire k k-1 //finementre scambiare v[i] con v[k] //finementre: ciclo esterno //sistemare conf nella posizione se v[k] > conf allora k k-1 //finese scambiare v[n1] con v[k] //fine partizione k=i: è al suo posto E necessario il confronto tra conf e v[k]? 4

5 Esempio conf i=2 i=3 k=6 k= i=4 i=5 k=5 i = k = 5 termina anche il ciclo esterno v[k]>conf (10>13) quindi k Esempio conf i=2 i=3 i=4 i=5 i=6 i=7= k i = k = 7 v[k]>conf falso : termina anche il ciclo esterno k non varia Complessità. Contiamo i confronti tra conf e gli elementi v[i]: 0 se n = 0,1 (n1<n2) T(n) = D(n) + C(n) + T(k-1) + T(n-k) D(n) è la complessità dell algoritmo partizione C(n) = 0 guardare le due parti dell array D(n) = O(n): n-1 confronti nei predicati dei cicli interni + 1 confronto per sistemare conf. Caso peggiore: vettore ordinato, la partizione è sbilanciata: T(n) = n + T(0) + T(n-1) = n + T(n-1) = = n + (n-1 + T(0) + T(n-2)) = n + n-1 + T(n-2) = = n + (n-1) + (n-2) + T(n-3) = =.. = n + (n-1) T(0) + T(n (n-1)) = = n (n-1)/2 O(n 2 /2) 5

6 Caso favorevole: conf sempre al centro: la partizione è bilanciata: L idea è la seguente: dividere l insieme in due parti uguali di n/2 componenti T(n) = n + T(n/2) + T(n/2) = n + 2T(n/2) = = n + 2(n/2 + 2T(n/4)) = 2n T(n/2 2 ) = =.. = k n + 2 k T(n/2 k ) n/2 n/2 se fossero già ordinate le potremmo riunire con un algoritmo di fusione (merge) se n = 2 k allora k = log 2 n O(n log 2 n) Esempio. Consideriamo i due array ordinati A e B e costruiamo l array MG che contiene gli elementi di A e B (con eventuali ripetizioni) in ordine: si considerano le prime componenti, quella più piccola viene inserita nell array MG, e si considera la sua successiva; quando uno dei due è terminato, basta ricopiare l altro (par. 3.5). A: B: MG: Per ordinare le due parti di n/2 componenti, usiamo in maniera ricorsiva la stessa strategia: dividere a metà, per poi fondere le parti ordinate, proseguendo fino ad un array di un solo elemento (par. 9.5). La dimensione limite è h=2: se n<2 c è un solo elemento. Vediamo quindi il progetto dell algoritmo mergesort per ordinare un array v dalla componente p alla componente q. 6

7 algoritmo mergesort(v, p, q) se p<q allora medio (p+q)/2 //troncata chiamare mergesort(v, p, medio) chiamare mergesort(v, medio+1, q) chiamare merge(v, p, medio, q) finese finemergesort Per gestire la fusione pensiamo all array diviso in due parti, da p a medio, e da medio+1 a q; inoltre usiamo un array di supporto s per appoggiare le componenti di v in ordine. Progetto dell algoritmo di fusione (merge) algoritmo merge(v,p,medio,q) h p i p k medio+1 mentre h medio e k q eseguire se v[h] v[k] allora s[i] v[h] h h+1 altrimenti s[i] v[k] k k+1 finese i i+1 finementre //ricopiare la parte di array non esaminata se h = medio+1 allora copiare in s la seconda parte altrimenti copiare in s la prima parte finese ricopiare s sul v //fine merge Esercizio. Implementare gli algoritmi quicksort e mergesort ed eseguire le prove dei tempi o contare le chiamate ricorsive. 7

8 Complessità. Contiamo i confronti tra gli elementi dell array: 0 se n = 0,1 T(n) = D(n) + C(n) + T(n/2) + T(n/2) D(n) = 0 calcolo di medio C(n) è la complessità dell algoritmo di fusione C(n) = O(n): vengono considerati tutti gli elementi delle due parti lunghe n/2 Il numero di confronti è sempre lo stesso perché anche se l array è ordinato si esegue sempre la divisione a metà e la fusione delle due parti; le partizioni sono bilanciate: T(n) = n + T(n/2) + T(n/2) = n + 2T(n/2) = = n + 2(n/2 + 2T(n/4)) = 2n T(n/2 2 ) = =.. = k n + 2 k T(n/2 k ) se n = 2 k allora k = log 2 n O(n log 2 n) e Confrontiamo i due algoritmi. L algoritmo mergesort ha la complessità più bassa nel caso peggiore O(nlog 2 n); esegue però molte ricopiature per eseguire la fusione. L algoritmo quicksort ha caso peggiore O(n 2 /2), ma nel caso favorevole e medio è O(nlog 2 n). Alcuni linguaggi (Java) implementano un algoritmo sort per il problema dell ordinamento utilizzando: l ordinamento per inserimento per n<7, e quicksort negli altri casi. Albero delle chiamate ricorsive. v0 v1 v2 v3 v4 v5 v6 v

9 Altri algoritmi per Fibonacci Altri algoritmi per Fibonacci I due seguenti algoritmi si basano sulle matrici. Consideriamo la matrice A e la matrice A n-1 : si può dimostrare per induzione 1 1 A= che la matrice A n-1 = A A.. A 1 0 n-1 volte 1 1 n-1 F n F n-1 A n-1 = = 1 0 F n-1 F n-2 Altri algoritmi per Fibonacci Esercizio. Verificare la formula per n=2, 3, 4. Si può allora costruire un algoritmo che calcola la potenza n-esima di A, matrice M, e restituisce il primo elemento di M, corrispondente a F n : intestazione funzione fibonacci4 (n intero) intero i M I //matrice identità per i da 1 a n-1 eseguire M M * A //fineper restituire M[0][0] //finealgoritmo Altri algoritmi per Fibonacci La complessità di tempo è O(n): infatti c è una struttura iterativa per calcolare il prodotto tra due matrici di dimensione 2 2 (un numero finito di prodotti e somme) La complessità di spazio è O(1): le matrici A, M, I occupano una quantità di spazio costante. Il prossimo algoritmo è una ottimizzazione dell algoritmo precedente: si può eseguire la potenza n-esima con un algoritmo basato sui quadrati. 9

10 Altri algoritmi per Fibonacci Esempio. Vogliamo calcolare = = = 4 4 = = 4 8 quindi in 3= log 2 8 passi abbiamo eseguito il calcolo. In generale: M n = ( M n/2 ) 2 con n pari Altri algoritmi per Fibonacci poiché la divisione è troncata, se n è dispari (n/2) 2 è uguale a ((n-1)/2) 2 = (n-1) occorre perciò un altra moltiplicazione per M. intestazione funzione fibonacci5 (n intero) M I chiama potenzamatrice(m, n-1) restituire M[0][0] //finealgoritmo Altri algoritmi per Fibonacci intestazione algoritmo potenzamatrice(matrice M, intero n) se n>1 allora potenzamatrice(m, n/2) M M * M //finese se n è dispari allora M M * A //finese //finealgoritmo La complessità di tempo è O(log 2 n) La complessità di spazio è O(1). Puntatori o riferimenti 10

11 Puntatori o riferimenti Puntatori o riferimenti Un puntatore è una variabile che contiene l indirizzo di un area di memoria. Quando si definisce una variabile, questa viene allocata in memoria e viene individuata dal suo nome. È possibile anche accedere alla variabile tramite il suo indirizzo. Per definire in C++ una variabile puntatore si utilizza il simbolo * e si indica il tipo di dato dell area di memoria. Sintassi. nometipo *nomepuntatore; Esempio. int i; i=5; int *p; p 5 i Puntatori o riferimenti Con la definizione int *p; si dice che p è un puntatore ad un area di memoria di tipo int. Pertanto p può contenere l indirizzo di memoria di una variabile di tipo int. Per ottenere l indirizzo di memoria di una variabile già allocata, si utilizza l operatore & operatore indirizzo_di Puntatori o riferimenti Per collegare il puntatore p all area allocata per la variabile i eseguiamo l assegnazione: p=&i; p In tale modo i si può accedere ad i anche tramite p: *p è il contenuto dell area vista da p. 5 11

12 Puntatori o riferimenti Tramite il puntatore p possiamo variare il contenuto dell area relativa alla variabile i. Esempio. *p = 27; 27 cout<<i; il valore stampato per i sarà 27. p i 12

Tecniche Algoritmiche: divide et impera

Tecniche Algoritmiche: divide et impera Tecniche Algoritmiche: divide et impera Una breve presentazione F. Damiani - Alg. & Lab. 04/05 Divide et impera (o Divide and conquer) Per regnare occorre tenere divisi i nemici e trarne vantaggio F. Damiani

Dettagli

Esercizi per il corso di Algoritmi, anno accademico 2011/12

Esercizi per il corso di Algoritmi, anno accademico 2011/12 Esercizi per il corso di Algoritmi, anno accademico 2011/12 Esercizi sulla Tecnica Divide et Impera N.B. Tutti gli algoritmi vanno scritti in pseudocodice (non in Java, nè in C++, etc. ). Di tutti gli

Dettagli

Tempo e spazio di calcolo (continua)

Tempo e spazio di calcolo (continua) Tempo e spazio di calcolo (continua) I numeri di Fibonacci come case study (applichiamo ad un esempio completo le tecniche illustrate nei lucidi precedenti) Abbiamo introdotto tecniche per la correttezza

Dettagli

Gli algoritmi ricorsivi di ordinamento. Paolo Camurati Dip. Automatica e Informatica Politecnico di Torino

Gli algoritmi ricorsivi di ordinamento. Paolo Camurati Dip. Automatica e Informatica Politecnico di Torino ordinamento Paolo Camurati Dip. Automatica e Informatica Politecnico di Torino Merge Sort Ricorsivo, divide et impera Stabile Divisione: due sottovettori SX e DX rispetto al centro del vettore. p r A.A.

Dettagli

Algoritmi e Strutture Dati

Algoritmi e Strutture Dati Algoritmi e Strutture Dati Capitolo 1 Un introduzione informale agli algoritmi Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano Definizione informale di algoritmo Insieme di istruzioni, definite

Dettagli

Trasformare array paralleli in array di record

Trasformare array paralleli in array di record Trasformare array paralleli in array di record Un array è una struttura di dati omogenea: gli elementi dell array sono tutti dello stesso tipo (che è il tipo dell array). A volte è necessario gestire informazioni

Dettagli

Un esempio di calcolo di complessità: insertion sort

Un esempio di calcolo di complessità: insertion sort Un esempio di calcolo di complessità: insertion sort Vediamo su un esempio come si può calcolare la complessità di un algoritmo... L esempio è un metodo semplice per ordinare arrays: insertion sort, o

Dettagli

Analisi algoritmi ricorsivi e relazioni di ricorrenza

Analisi algoritmi ricorsivi e relazioni di ricorrenza Analisi algoritmi ricorsivi e relazioni di ricorrenza Punto della situazione Finora abbiamo affrontato: il tempo di esecuzione di un algoritmo, l analisi asintotica con le notazioni asintotiche e la tecnica

Dettagli

Algoritmi di ordinamento: Array e ricorsione

Algoritmi di ordinamento: Array e ricorsione Laboratorio di Algoritmi e Strutture Dati Aniello Murano http://people.na.infn.it people.na.infn.it/~murano/ 1 Algoritmi di ordinamento: Array e ricorsione 2 1 Indice Algoritmi di ordinamento: Insertion

Dettagli

Lo sviluppo di un semplice programma e la dimostrazione della sua correttezza

Lo sviluppo di un semplice programma e la dimostrazione della sua correttezza Il principio di induzione Consideriamo inizialmente solo il principio di induzione per i numeri non-negativi, detti anche numeri naturali. Sia P una proprietà (espressa da una frase o una formula che contiene

Dettagli

Albero di Riscorsione

Albero di Riscorsione Albero di Riscorsione Albero di ricorsione Un albero di ricorsione è un modo di visualizzare cosa accade in un algoritmo divide et impera L etichetta della radice rappresenta il costo non ricorsivo della

Dettagli

Lista di esercizi 11 maggio 2016

Lista di esercizi 11 maggio 2016 Lista di esercizi 11 maggio 2016 1. Determinare il numero di sequenze binarie di lunghezza n che contengano almeno una coppia di 0 consecutivi. Soluzione. Potrebbe essere utile un programma di calcolo

Dettagli

5. DIVIDE AND CONQUER I

5. DIVIDE AND CONQUER I Divide-et-Impera (Divide and conquer) 5. DIVIDE AND CONQUER I Mergesort e Relazioni di ricorrenza Esempi di progettazione D&I Moltiplicazione di interi Contare inversioni Divide-et-Impera. Definizione

Dettagli

Cammini minimi fra tutte le coppie

Cammini minimi fra tutte le coppie Capitolo 12 Cammini minimi fra tutte le coppie Consideriamo il problema dei cammini minimi fra tutte le coppie in un grafo G = (V, E, w) orientato, pesato, dove possono essere presenti archi (ma non cicli)

Dettagli

Algoritmi e Strutture Dati

Algoritmi e Strutture Dati Algoritmi Ricorsivi e Maria Rita Di Berardini, Emanuela Merelli 1 1 Dipartimento di Matematica e Informatica Università di Camerino A.A. 2006/07 I conigli di Fibonacci Ricerca Binaria L isola dei conigli

Dettagli

Algoritmi e Strutture Dati

Algoritmi e Strutture Dati Algoritmi e Strutture Dati Informazioni sul corso + Un introduzione informale agli algoritmi Domenico Fabio Savo 1 Domenico Fabio Savo Email: [email protected] Web: http://www.dis.uniroma1.it/~savo

Dettagli

2. Analisi degli Algoritmi

2. Analisi degli Algoritmi 2. Analisi degli Algoritmi Introduzione 2.1 Un modello di macchina elementare: la Macchina a Registri 2.2 Costo di esecuzione di un programma 2.3 Analisi del costo di esecuzione: il modello a costi uniformi

Dettagli

Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base

Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base Dati e Algoritmi I (Pietracaprina): Esercizi 1 Problema 1. Sia T una stringa arbitraria di lunghezza n 1 su un alfabeto Σ. È sempre possibile

Dettagli

Programmazione dinamica

Programmazione dinamica Programmazione dinamica Violetta Lonati Università degli studi di Milano Dipartimento di Informatica Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica Violetta Lonati Programmazione

Dettagli

Parte 1: tipi primitivi e istruzioni C

Parte 1: tipi primitivi e istruzioni C Parte 1: tipi primitivi e istruzioni C Esercizio 1 Scrivere un programma che stampa la somma di una sequenza di N numeri inseriti dall utente. Esercizio 2 Scrivere un programma che stampa la somma di una

Dettagli

Algoritmi greedy. Gli algoritmi che risolvono problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione

Algoritmi greedy. Gli algoritmi che risolvono problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione Algoritmi greedy Gli algoritmi che risolvono problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione Gli algoritmi greedy sono algoritmi basati sull idea

Dettagli

Esempio : i numeri di Fibonacci

Esempio : i numeri di Fibonacci Esempio : i numeri di Fibonacci La successione di Fibonacci F 1, F 2,... F n,... è definita come: F 1 =1 F 2 =1 F n =F n 1 F n 2,n 2 Leonardo Fibonacci (Pisa, 1170 Pisa, 1250) http://it.wikipedia.org/wiki/leonardo_fibonacci

Dettagli

ALGORITMI Docente: Prof. Domenico Cantone

ALGORITMI Docente: Prof. Domenico Cantone CORSO SPECILE DI DURT NNULE PER IL CONSEGUIMENTO DELL BILITZIONE LL INSEGNMENTO NELL SCUOL SECONDRI DI I e II GRDO Indirizzo Fisico - Informatico - Matematico a.a. 00/07 - Classe - Informatica LGORITMI

Dettagli