...

1 - Università di Camerino

by user

on
Category: Documents
9

views

Report

Comments

Transcript

1 - Università di Camerino
Algoritmi e Strutture Dati
Università di Camerino
Corso di Laurea in Informatica
(12 CFU)
I periodo didattico
Emanuela Merelli
email:[email protected]
Lezione 3
Tecniche di Progettazione
Argomento: Divide et Impera
Obiettivo conoscitivo:
Tecniche
Algoritmiche:
Divide et Impera
Tecniche di progettazione di
algoritmi
• Approccio Incrementale
– Insertion sort: Se è ordinato A[1..j-1] si inserisce A[j] ...
• Approccio Divide et impera
– Merge sort: divido il problema in n sottoproblemi e
opero ricorsivamente sugli n problemi
• Programmazione Dinamica
–…
Divide-et-impera
Un algoritmo si dice ricorsivo se al suo interno (tra i
suoi comandi) sono presenti chiamate a se stesso
per gestire sottoproblemi analoghi a quello dato
L’approccio seguito dagli algoritmi ricorsivi è quello di
suddividere il problema dato in sottoproblemi simile a
quello di partenza ma di dimensione inferiore
Quindi, una volta che i sottoproblemi sono stati risolti
ricorsivamente, combinare le soluzioni trovate per
creare la soluzione al problema dato
Divide
Impera
Combina
Divide et Impera
• Divide et impera:
– Divide: Se l’istanza del problema da risolvere è troppo
“complicata” per essere risolta direttamente, dividila in due o più
“parti”
– Risolvi ricorsivamente: Usa la stessa tecnica divide et impera
per risolvere le singole parti (sottoproblemi)
– Combina: Combina le soluzioni trovate per i sottoproblemi in
una soluzione per il problema originario.
MergeSort: Algoritmo
Dividi: se S contiene almeno due elementi (un solo
elemento è banalmente già ordinato), rimuovi tutti gli
elementi da S e inseriscili in due vettori, S1 e S2, ognuno
dei quali contiene circa la metà degli elementi di S. (S1
contiene i primi n/2 elementi e S2 contiene i rimanenti n/2
elementi).
Risolvi ricorsivamente: ordina gli elementi in S1 e S2
usando MergeSort (ricorsione).
Combina: fondi gli elementi di S1 e S2 ottenendo un unico
vettore S ordinato (merge)
Mergesort: esempio 2
24
10
21
36
24
10
36
87
39
83
58
21
39
83
58
87
24
10
24
36
36
10
87
83
21
39
21
58
39
83
58
24
36
10
87
24
36
Merge Sort: Algoritmo
Merge-sort(A,p,r)
if p < r then
q= └(p+r)/2┘
Merge-sort(A,p,q)
Merge-sort(A,q+1,r)
Merge(A,p,q,r)
Merge(A,p,q,r)
Rimuovi il più piccolo dei due elementi
affioranti in A[p..q] e A[q+1..r] e inseriscilo
nel vettore in costruzione.
Continua fino a che i due vettori sono svuotati.
Copia il risultato in A[p..r].
Esempio 1
A = <5,2,4,6,1,3,2,6>
12234566
fusione
2456
1236
fusione
25
fusione
5
2
4
fusione
46
13
fusione
fusione
6
1
26
fusione
3
Sequenza iniziale
2
6
Merge
1
12
27
36
38
47
54
1
23
25
32
68
96
12 23
… e così via
Ricorrenze
Quando un algoritmo contiene una chiamata ricorsiva a se stesso, il
suo tempo di esecuzione può spesso essere descritto da una
equazione di ricorrenza o ricorrenza.
Una ricorrenza è una equazione o una disequazione che descrive una
funzione in termini del suo valore su input sempre più piccoli.
Un'equazione ricorsiva esprime il valore di f(n) come combinazione di
f(n1),...,f(nk) dove ni < n, i=1..k.
Equazioni ricorsive
Indichiamo con T(n) il tempo di esecuzione di un problema di
dimensione n. E con (1) un tempo costante
Suddividiamo un problema in a sottoproblemi, ciascuno dei quali ha
una dimensione 1/b rispetto al problema principale e supponiamo di
impiegare un tempo D(n) per suddividere e un tempo C(n) per
combinare le soluzioni dei sottoproblemi. Si ottiene la seguente
ricorrenza:
(1)
se n < c
T(n) =
aT(n/b) + D(n) + C(n) se n > c
Esempio del Merge Sort
(1)
se n=1
2T(n/2) + (n)
se n > 1
T(n) =
Dove:
Divide in un tempo (1)
Impera in 2T(n/2)
Combina in (n)
Equazioni ricorsive:
un esempio semplice
1
se n = 1
T(n/2) + 1
se n > 1
T(n) =
Come si risolve ???
Metodo iterativo
T(n) =
T(n/2)
+ 1
T(n/4)
+1
+ 1
T(n/8)+1
+1
+ 1
.....................
T(n/n)+1
.........................
+ 1
1 + 1 .........................
+ 1
k
Ci fermiamo quando
2k=n
Dobbiamo valutare k
sappiamo che 2k = n, quindi
log2( 2k ) = log2(n), ovvero
k = log2(n)
Induzione
Dobbiamo dimostrare che una affermazione
è vera per ogni n≥0
Teorema.
se
1. affermazione(0) è vera.
2. affermazione(n-1) vera implica
affermazione(n) vera.
Allora affermazione(n) vera per ogni n ≥ 0
Dimostrazione per induzione:
esempio
n
affermazione(n) =
i
= n(n+1)/2
i=1
1
affermazione(1) =
i

i=1
= 1(1+1)/2 = 1
OK
affermazione(n-1) ----> affermazione(n):
n-1
i = (n-1)(n)/2 ---->
i=1

n
i

i=1
= n(n+1)/2
Dimostrazione per induzione:
esempio
n-1
i + n = (n-1)(n)/2 + n = n(n+1)/2
i =
i=1
i=1
n
...ma


L’uguaglianza tra questi due termini non è altro che affermazione(n-1)
e quindi la assumiamo vera per ipotesi induttiva.
Metodo di sostituzione
Primo passo:
Tentiamo di “indovinare” una possibile soluzione:
T(n) ≤ clog2(n)
Secondo passo:
la verifichiamo per induzione come segue:
Assumiamo che T(n’) ≤ clog2(n’) per n’ < n
e dimostriamo che T(n) ≤ clog2(n)
c è una costante (indipendente da n) che determineremo strada facendo…
T(n) = T(n/2) + 1

≤ clog2(n/2)
+ 1
= clog2(n) - clog2(2)
= clog2(n) - c + 1
se c ≥ 1 allora
≤
clog2(n)
Ipotesi induttiva !!!
+ 1
Equazioni ricorsive:
un esempio più complicato
(1)
se n = 1
2T(n/2) + (n)
se n > 1
T(n) =
Soluzione T(n) = (n log(n))
Albero di ricorsione
Cn + 2T(n/2)
C(n/2) + 2T(n/4)
C(n/4) + 2T(n/8)
……
(1)
(1)
C(n/2) + 2T(n/4)
C(n/4) + 2T(n/8)
……
……
C(n/4) + 2T(n/8)
……
…… …… ……
C(n/4) + 2T(n/8)
=cn
+
=cn
+
=cn
+
……
(1)
(1)
=cn
= n(log(n))
Il fattore log(n) deriva dal fatto che
l’albero ha un altezza log(n)
“Master Method o
Metodo dell’esperto”
•T(n) = aT(n/b) + f(n)
a  1, b > 1, f(n) > 0
Poniamo x = logba
f(n) = O(nx-) con >0
allora
T(n) = (nx)
f(n) = (nx)
allora
T(n) = (nx log(n))
f(n) = (nx+) con >0
af(n/b) ≤ cf(n) con c<1
per tutti gli n>n0
allora T(n) = (f(n))
… Merge sort T(n) = (n log(n))
Insertion sort
Merge sort
Worst case
(n2)
(n log(n))
Average case
(n2)
(n log(n))
(n)
(n log(n))
Best case
Perchè ordinare è importante
•... velocizza molto la ricerca !!!
Binary-search(A,x)
i=0
j=length(A)-1
while i<j do
k=(i+j)/2
if A[k]=x then return true
if A[k]>x then j=k-1
if A[k]<x then i=k+1
if A[i]=x then return true
else return false
Analisi di Binary search
•D(t)=j-i
al tempo t
•D(0) = n-1
•.........
•D(t+1) = D(t)/2
•Usciamo dal while quando D(t)<2
•... ... ovvero se t ≥ log2n.
•Quindi T(n) = (log2n)
Priority Queue (Code a Priorità)
•Dati: un insieme di elementi, ognuno dei quali ha
una chiave (un intero per esempio).
•Operazioni: inserimento, trova il massimo,
estrazione del massimo (massima chiave).
•Applicazioni delle PQ:
Job scheduling
Event-driven simulations
Implementazione (facile)
usando vettori
•Prima soluzione: vettore ordinato.
Ricerca massimo:
(1) operazioni
estrazione massimo:
(1) operazioni
inserimento:
(n) operazioni
•Seconda soluzione vettore non ordinato.
•
Ricerca massimo:
(n) operazioni
estrazione massimo:
(n) operazioni
inserimento:
(1) operazioni
•Si può fare meglio ???
Grafi e Alberi
•G=(V,E)
{1,3,4,1} è un ciclo
Un grafo senza cicli
è aciclico
V={1,2,3,4,5,6,7,8}
E={(1,2),(1,3),(1,4),(3,4),(6,7),(7,8)}
1
4
6
2
7
3
5
8
Un albero è un grafo aciclico con un numero di nodi
uguale al numero di archi più uno ( |E|=|V|-1 )
1
Albero
3
4
7
5
3
8
6
2
1
4
6
2
Foresta
5
7
8
Radice
r
h(a) altezza del nodo a:
h(x)=1
h(y)=h(q)=2
h(w)=3
x
y
q
w
Foglie
r è la radice
x è il padre di y
y è un figlio di x
x e q sono avi di w
w e q sono discendenti di x
q è fratello di y
Fly UP