Algoritmi e Strutture Dati
Capitolo 4
Ordinamento: lower bound Ω(n log n) e
MergeSort
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Richiamo: Delimitazione superiore alla complessità
temporale di un algoritmo
Ricorda:
Un algoritmo A ha tempo di esecuzione T(n)=O(f(n)) su istanze di
dimensione n se la quantità T(n) di tempo sufficiente per eseguire A su
ogni istanza di dimensione n (e quindi in particolare anche nel caso
peggiore) verifica la relazione
T(n)=O(f(n))
Convenzioni:
1. Se scriverò che un algoritmo ha complessità T(n) = O(f(n)),
intenderò che su ALCUNE istanze costerà Θ(f(n)), ma sulle
rimanenti costerà o(f(n) (esempio, l’IS).
2. Se scriverò che un algoritmo ha complessità T(n)=Θ(f(n)),
intenderò che su TUTTE le istanze costerà Θ(f(n)) (esempio, il SS)
2
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Richiamo: Delimitazione inferiore alla complessità
temporale di un algoritmo
Ricorda:
Un algoritmo A ha tempo di esecuzione T(n)=(f(n)) su istanze di
dimensione n se la quantità di tempo necessaria per eseguire A nel caso
peggiore (e quindi non è detto che debba essere necessaria per ogni
istanza di dimensione n: istanze facili potrebbero richiedere meno
risorse!) verifica la relazione
Tworst(n)= (f(n))
3
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Richiamo: Complessità di un problema
Ricorda: (upper bound di un problema)
Un problema P ha una delimitazione superiore alla
complessità temporale O(f(n)) se esiste un algoritmo
che risolve P il cui tempo di esecuzione è O(f(n))
Ricorda: (lower bound di un problema)
Un problema P ha una delimitazione inferiore alla
complessità temporale (complessità intrinseca) (f(n)) se
ogni algoritmo (anche quelli non ancora progettati!) che
risolverà P avrà almeno un’istanza con tempo di esecuzione
(f(n))
4
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Convenzione
• Da ora in poi, quando parlerò di UB di un problema,
mi riferirò alla complessità del MIGLIORE
ALGORITMO che sono stato in grado di progettare
sino a quel momento (ovvero, quello con minore
complessità nel caso peggiore).
• Da ora in poi, quando parlerò di LB di un problema, mi
riferirò alla PIÙ GRANDE delimitazione inferiore che
sono stato in grado di dimostrare sino a quel momento.
5
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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?
6
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Ordinamento per confronti
Dati due elementi ai ed aj, per determinarne l’ordinamento relativo
effettuiamo una delle seguenti operazioni di confronto:
a i  aj ; ai  aj ; a i  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.
7
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Lower bound (n log n) per l’ordinamento
• Consideriamo un generico algoritmo A, che ordina
eseguendo solo confronti: dimostreremo che A esegue (nel
caso peggiore) (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
8
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Alberi 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 a una
dimensione dell’istanza
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio
Input <a1,a2,a3>
Š
1,2,3
1:2
Š
2:3
Š
1,3,2
Š

1:3


3,1,2
2,1,3
1:3
Š
2,3,1
Riconoscete
l’algoritmo
associato?

2:3

3,2,1
È proprio l’Insertion Sort!
Esercizio per casa: costruire l’albero di decisione
per il SS su una sequenza di 3 elementi.
10
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Alcune definizioni
Sotto-albero
sinistro
Š
1,2,3
2:3
Š
1,3,2
radice
1:2
Š
1:3


Š


3,1,2
Sotto-albero
destro
2,1,3
1:3
Š
2,3,1

2:3

3,2,1
Profondità di un nodo: lunghezza del cammino (in termini di numero
di archi) che lo congiunge alla radice.
Altezza di un albero: valore massimo della profondità dei nodi.
11
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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
12
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Altezza in funzione delle foglie
Lemma: Un albero binario con k foglie in cui ogni nodo
interno ha esattamente due figli, 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
13
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Il lower bound (n logn)
• 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 =
Formula di Stirling:
n!  (2pn)1/2 ·(n/e)n
> (n/e)n
14
= n log2 (n/e) =
= n log2 n – n log2 e =
= (n log n)
QED
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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:
1 Divide: dividi l’array a metà
2 Risolvi il sottoproblema ricorsivamente
3 Impera: fondi le due sottosequenze ordinate
15
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio di esecuzione
16
7 2 4 5 3 1 5 6
input
1 2 3 4 5 5 6 7
output
7 2 4 5
3 1 5 6
2 4 5 7
1 3 5 6
7 2
4 5
3 1
5 6
2 7
4 5
1 3
5 6
Input ed
output delle
chiamate
ricorsive
7
2
4
5
3
1
5
6
7
2
4
5
3
1
5
6
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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]
17
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Algoritmo di fusione di sequenze ordinate
Merge (A, i1, f1, f2)
1.
Sia X un array ausiliario di lunghezza f2-i1+1
2.
i=1
3.
i2=f1+1
4.
while (i1 f1 e i2  f2) do
5.
if (A[i1]  A[i2])
6.
then X[i]=A[i1]
7.
8.
9.
incrementa i e i1
Osservazione: usa
l’array ausiliario X
else X[i]=A[i2]
incrementa i e i2
10.
if (i1<f1) then copia A[i1;f1] alla fine di X
11.
else copia A[i2;f2] alla fine di X
12.
copia X in A[i1;f2]
18
fonde A[i1;f1] e A[f1+1;f2]
output in A[i1;f2]
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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)
19
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
MergeSort
MergeSort (A, i, f)
1.
if (i  f) then return
2.
m = (i+f)/2
3.
MergeSort(A,i,m)
4.
MergeSort(A,m+1,f)
5.
Merge(A,i,m,f)
20
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Tempo di esecuzione
• Il numero di confronti del MergeSort è descritto dalla seguente
relazione di ricorrenza:
C(n) ≤ 2 C(n/2) + Θ(n)
C(1)=1
(si noti che f(n)=Θ(n), in quanto il numero di confronti nelle fusioni è
ovviamente C(n)=O(n), ma anche C(n)=Ω(min{n1,n2})=Ω(min{n/2,
n/2})=Ω(n))
• Usando il caso 2 del Teorema Master (infatti a=b=2, e quindi
f(n)Θ(n)=Θ(nlog22)Θ(nlogba)), si ottiene
C(n) = O(nlog22 log n) = O(n log n)
(si noti che utilizzo la notazione O in quanto nella relazione di
ricorrenza compare il simbolo ≤)
• Infine, per il tempo di esecuzione totale (confronti + copie), si ha:
T(n) = 2 T(n/2) + Θ(n) T(1)=1  T(n) = Θ(n log n)
(si noti che in questo caso utilizzo la notazione Θ in quanto nella
relazione di ricorrenza compare il simbolo =)
21
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Più precisamente…
1. 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))
2. Nel caso medio, il MS esegue (n ⌈log n⌉ 2⌈log n⌉ + 1) – 0.2645·n confronti
3. Nel caso migliore (array già ordinato), il MS
esegue n-1 confronti
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
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)
23
Copyright © 2004 - The McGraw - Hill Companies, srl