Clicca qui.

annuncio pubblicitario
Algoritmi di ordinamento ottimali
L’algoritmo Merge-Sort ha complessità O(n log n) 
Algoritmo di ordinamento ottimale.
A differenza degli algoritmi IS e SS, Merge-Sort
non è però un algoritmo di ordinamento in loco.
Infatti, la procedura Merge(A,p,q,r) richiede un
vettore di appoggio di dimensione r-p+1 in cui
effettuare la fusione
 È facile convincersi del fatto che il Merge-Sort
ha complessità spaziale S(n)=O(n log n) (infatti ho
bisogno di O(n) spazio ausiliario per ognuno dei log n
livelli dell’albero della ricorsione)
 Ciò comporta (insieme alla gestione della
struttura ricorsiva) anche una spesa in termini di
tempo effettivo dell’esecuzione (infatti, lo spazio
ausiliario richiesto non eccede O(n log n) e quindi
non modifica l’andamento asintotico temporale, ma il
tutto si riflette sulle costanti moltiplicative!)
Algoritmi e strutture Dati Lezione 7
1
Algortimo di ordinamento ottimale in loco: Heapsort
Introduciamo un nuovo algoritmo di ordinamento detto
Heap-Sort che ha le seguenti caratteristiche:
- T(n) = O(n log n)  Alg. Ordinamento ottimale
- Ordina in loco e quindi S(n)=O(n)
Per fare ciò dobbiamo introdurre una struttura di dati
detta heap.
Heap binario = albero binario in cui ogni nodo figlio ha
valore minore o uguale al valore del proprio nodo padre.
Es.
16
14
10
7
8
2
4
9
3
1
L’albero è quasi completo  Completo su tutti i livelli
tranne eventualmente sul livello più basso che è riempito da
sinistra.
Altezza dell’albero  lunghezza del più lungo cammino
discendente dalla radice ad una foglia.
Algoritmi e strutture Dati Lezione 7
2
Proprietà di un heap
Notiamo che:
16
14
In questa
direzione è
presente un
ordinamento
10
7
8
2
4
9
3
1
In questa direzione non è
presente un ordinamento.
Proprietà di ordinamento parziale dello heap:
Ogni nodo interno contiene un valore maggiore uguale del
valore contenuto nei figli. Da ciò segue che:
1.
2.
l’elemento più grande dello heap è memorizzato nella
radice.
ogni nodo interno contiene un valore maggiore uguale
del valore contenuto in tutti i suoi discendenti.
Algoritmi e strutture Dati Lezione 7
3
Come rappresentare uno heap: dall’albero binario all’array
i=1
16
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
7
9
3
Un albero binario quasi completo può essere
descritto da un array in cui il figlio sinistro ed il
figlio destro di un nodo i si trovano nelle posizioni
2i e 2i+1 rispettivamente.
i=1
2
3
4
5
6
7
8
9
10 … … Length[A]
16
14
10
8
7
9
3
2
4
1
…
…
…
Heap-size[A]
N.B. Stiamo assumendo che
l’indice i parta da 1.
Algoritmi e strutture Dati Lezione 7
4
i=1
16
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
7
9
3
i=1
2
3
4
5
6
7
8
9
10 … … Length[A]
16
14
10
8
7
9
3
2
4
1
…
…
…
Heap-size[A]
Heap-size[A] ≤ Length[A]
Per muoverci all’interno dell’albero definiamo le
seguenti procedure:
Parent(i)
returni/2
Left(i)
Return 2i
Right(i)
Return 2i+1
Affinché un array A che rappresenta un albero binario sia
uno heap deve valere la relazione:
A(parent[i])  A[i]
per ogni i  1
Algoritmi e strutture Dati Lezione 7
5
Mostreremo che un array generico può essere ordinato
trasformandolo in un heap ed eseguendo operazioni che
hanno tempo di esecuzione al più proporzionale alla
altezza H dello heap.
Notiamo:
i=1
16
H=3
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
9
7
3
H = altezza albero binario
Se l’albero è completo:
n = 1 +2 + 22 + … + 2H = 2H*( 1 + (1/2) + … + (1/2)H)=
= 2H*(2-(1/2)H) = 2H+1 –1
Se l’albero è quasi completo:
2H -1 < n < 2 H+1 –1  H = (log(n))
Algoritmi e strutture Dati Lezione 7
6
Algoritmo Heapsort - strategia
L’ idea di base è la seguente:
 Trasformiamo un array A di dimensione n in un heap di
dimensione n (creazione dell’heap);
 Passo 1: Per le proprietà dello heap, sappiamo che
l’elemento massimo della sequenza iniziale è
memorizzato in A[1]. Scambiamo A[1] con l’elemento
A[n];
 La sequenza A[1]……A[n-1] che otteniamo non è più uno
heap (A[1] è fuori posto). Permutiamo i suoi elementi in
moto da trasformarla in un heap di dimensione n-1
(mantenimento dell’heap);
Passo 2: Per le proprietà dello heap, sappiamo che
l’elemento massimo della sequenza A[1]……A[n-1] è
memorizzato in A[1]. Scambiamo A[1] con l’elemento A[n1];
 ……
 ……
Ripetendo n-1 volte otteniamo una sequenza ordinata.
Le operazioni che effettuiamo sono:
o Creazione di un heap
O(n)
Agli step k=1,2,…n-1:
o Scambio di due elementi O(1) (temporale e spaziale)
o Mantenimento dello heap
O(log n)
Poiché abbiamo n-1 iterazioni  T(n)=O(n log n)
…e poiché eseguiamo il tutto in loco  S(n)=O(n)
Algoritmi e strutture Dati Lezione 7
7
Procedura di mantenimento dell’heap
Supponiamo che A sia uno heap. Alteriamo il valore di
A[1]. L’array che otteniamo non è più un heap.
I sottoalberi con radice in A[right(1)] ed A[left(1)] sono
ancora heap. Dobbiamo scrivere una procedura che
permuti gli elementi A[1],A[2],……,A[heap-size[A]] in
modo da ricostruire uno heap.
FixHeap(A,i)
lleft(i)
rright(i)
If (l heap-size[A]) and (A[l] > A[i])
then largest  l
else largest  i
If (r  heap-size[A] )and(A[r] > A[largest])
then largest  r
If (largest  i)
then scambia(A[i], A[largest])
FixHeap(A,largest)
La procedura FixHeap fa “scendere” A[i] nella prima
posizione utile.
Ipotesi necessaria per la correttezza- I sottoalberi con
radice in A[right(i)] ed A[left(i)] sono heap.
Tempo di esecuzione di FixHeap(A,i)  O(hi)
hi = altezza del nodo i (il livello più basso delle foglie ha
altezza 0)
Algoritmi e strutture Dati Lezione 7
8
FixHeap - esempio
i=1
16
2
3
4
10
4
5
14
7
8
9
10
2
8
1
6
7
9
3
i=1
Lancio FixHeap(A,2):
16
2
3
14
10
4
5
4
7
8
9
10
2
8
1
6
7
9
3
i=1
16
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
9
Algoritmi e strutture Dati Lezione 7
7
3
9
Procedura di creazione di uno heap
La procedura FixHeap può essere usata in modo bottom-up
per convertire un array A[1…n], in uno heap di lunghezza n.
Heapify(A)
heap-size[A]  lenght[A]
For i  lenght[A]/2 down to 1
do FixHeap(A,i)
Heapify “attraversa” i nodi non foglia dell’ heap, dal
basso verso l’alto ed esegue FixHeap su ciascuno di
essi.
 Ad ogni step le ipotesi necessarie per applicare
FixHeap sono automaticamente verificate.
Tempo di esecuzione di Heapify?
T(n) 
T
FixHeap
nodi di
altezza 1
H
H
h 1
h 1
  N nodi h   TFixHeap h    N nodi h   Oh 
H = altezza albero  log2(n)
Nnodi(h) = numero di nodi con altezza h  n/2h+1

n
h
T(n)  C   h 1  h  C  n   h 1  C  n  O(n)
h 1 2
h 1 2
log(n)
Notare – Si può costruire un heap da un array non
ordinato in tempo lineare!
Algoritmi e strutture Dati Lezione 7
10
Heapify – Un esempio
i=1
4
2
3
1
3
4
5
2
16
8
9
10
14
8
7
6
7
9
10
i=1
4
2
3
1
3
4
5
2
16
8
9
10
14
8
7
6
7
9
10
i=1
4
2
3
1
3
4
5
14
16
8
9
10
2
8
7
6
9
Algoritmi e strutture Dati Lezione 7
7
10
11
Heapify – Un esempio (2)
i=1
4
2
3
1
10
4
5
14
16
8
9
10
2
8
7
6
7
9
3
i=1
4
2
3
16
10
4
5
14
1
8
9
10
2
8
7
6
7
9
3
i=1
4
2
3
16
10
4
5
14
7
8
9
10
2
8
1
6
9
Algoritmi e strutture Dati Lezione 7
7
3
12
Heapify – Un esempio (3)
i=1
16
2
3
4
10
4
5
14
7
8
9
10
2
8
1
6
7
9
3
i=1
16
2
3
14
10
4
5
4
7
8
9
10
2
8
1
6
7
9
3
i=1
16
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
9
7
3
E’ un heap!
Algoritmi e strutture Dati Lezione 7
13
Algoritmo Heapsort
Heapsort(A)
Heapify(A)
For i length(A) down to 2
do Scambia(A[1],A[i])
Heapsize[A] Heapsize[A]-1
FixHeap(A,1)
O(n)
O(n)
O(n)
O(n)
O(n log n)
Tempo di esecuzione  O(n log n)
Ordinamento in loco
Esempio
Input: A=<4,1,3,2,16,9,10,14,8,7>
Heapify(A)  A0 =<16,14,10,8,7,9,3,2,4,1>
Scambia(A[1],A[n])
i=1
16
2
3
14
10
4
5
8
7
8
9
10
2
4
1
6
9
Algoritmi e strutture Dati Lezione 7
7
3
14
Heap-size = Heap-size -1
i=1
1
2
3
14
10
4
5
8
7
8
9
10
2
4
16
FixHeap(A,1)
6
7
9
3
i=1
14
2
3
8
10
4
5
4
7
8
9
10
2
1
16
6
9
Algoritmi e strutture Dati Lezione 7
7
3
15
Scambia(A[1],A[n-1])
i=1
14
2
8
4
4
5
7
9
1
8
2
3
10
6
9
7
3
10
16
Heap-size = Heap-size -1
i=1
1
2
8
4
4
5
7
8
2
14
i=1
10
2
8
4
4
5
7
14
6
9
7
3
10
16
FixHeap(A,1)
8
2
3
10
3
9
6
1
7
3
10
16
E cosi via ……
Algoritmi e strutture Dati Lezione 7
16
Scarica