Ordinamento
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 1
Algoritmi e Strutture Dati
Domenico Fabio Savo
Problema: dato un insieme S di n oggetti presi da undominio totalmente ordinato, ordinare S
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Ordinamento
• Subroutine in molti problemi
E’ possibile effettuare ricerche in array ordinati in tempo O(log n) (ricerca binaria)
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.
2
• Numerosissimi algoritmi
• Tre tempi tipici: O(n2), O(n log n), O(n)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Algoritmi e tempi tipici
n
n log2 n
n2
10
~ 33
100
100
~ 665
104
1000
106
106
~ 2·107
1012
109
1018
~ 104 ~ 3·1010
3
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Algoritmi di ordinamento
4
Approccio incrementale
Approccio incrementale:
• Supponiamo che k elementi di un array di n siano già
ordinati.
• Estendiamo l’ordinamento da k a k+1.
Come fare?
• selectionSort
• insertionSort
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 5
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
SelectionSort
1 2 4 5 3 7
7 2 4 5 3 1
1 2 4 5 3 7
1 2 3 5 4 7
1 2 3 4 5 7
1 2 3 4 5 7
1 2 3 4 5 7
Idea: estende l’ordinamento da k a k+1 elementi,
scegliendo il minimo degli n-k elementi non ancora
ordinati e mettendolo in posizione k+1
6
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
SelectionSort: pseudocodice
7
Algoritmo: selectionSort(array S di dimensione n)
int m;
//Seleziono l'elemento più piccolo nella porzione di array non ordinata
//e lo aggiungo come più grande elemento alla porzione ordinata.
//La porzione di array non ordinata va (ad ogni ciclo) da k a n-1
for(int k = 0; k<= n-2; k++){
m = k;
//Seleziona il più piccolo elemento nella pozione di array da
// ordinare. Tale elemento dovrà essere messo nella posizione k
for(int j = k+1; j < n; j++){
if(S[j] < S[m]) then m = j;
}
//Se l'elemento individuato si trova in una posizione m diversa da k
//scambia il valore nella posizione m con quello nella posizione k
if(m!=k) then swap(S, m, k);
//La funzione swap scambia tra loro i valori contenuti
//nelle posizioni n e k dell’array S
}
}
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
SelectionSort: analisi
Individuare il k-esimo minimo costa tempo O(n-k). Poichè
il ciclo esterno viene eseguito n-1 volte, il numero totale di
confronti è dato da:
k=0
n-2
O(n-k) i=1
n-1
i= ( O ) = O(n2)
usando il cambiamento di variabile i = n-k e la serie
aritmetica (vedere Paragrafo 17.2 in Appendice al libro).
8
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
InsertionSort
2 7 4 5 3 1
7 2 4 5 3 1
2 4 7 5 3 1
2 4 5 7 3 1
2 3 4 5 7 1
1 2 3 4 5 7
Idea: estende l’ordinamento da k a k+1 elementi,
posizionando l’elemento (k+1)-esimo nella posizione
corretta rispetto ai primi k elementi
9
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
InsertionSort: pseudocodice
10
Algoritmo: insertionSort(array S di dimensione n)
//comincio ad ordinare gli elementi dal secondo elemento nell'array
for(int k = 1; k < n; k++){
int elm = S[k]; //elem contiene l'elemento da riposizionare
//cerco l'indice del più piccolo elemento più grande di elm tra
//quelli che precedono elm in S
int p = k;
for(int j = 0; j < k; j++){
if(S[j] > elm) then{
p = j;
break;}
}
//Se p precede k, sposto elem da k a p. Prima devo spostare tutti
// gli elementi tra p e k-1 di una posizione in avanti.
if(p < k) then {
for(int i = k; i >= p+1; i--){
S[i] = S[i-1]; }
S[p] = elm; //ora che c’è spazio copio elm nella posizione p.
}
}
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
InsertionSort: analisi
L’inserimento del k-esimo elemento nella posizione
corretta rispetto ai primi k richiede tempo O(k) nel caso
peggiore
In totale, il tempo di esecuzione è pertanto:
k=1
n-1
k( O ) = O(n2)
usando la serie aritmetica
11
• Dopo la k-esima scansione, i k elementi più
grandi sono correttamente ordinati ed occupano le
k posizioni più a destra.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BubbleSort
Esegue una serie di scansioni dell’array:
– In ogni scansione confronta coppie di elementi
adiacenti, scambiandoli se non sono nell’ordine
corretto
– Dopo una scansione in cui non viene effettuato
nessuno scambio l’array è ordinato
12
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BubbleSort: esempio di esecuzione
2 4 5 3 1 7
7 2 4 5 3 1
2 4 3 1 5 7
72
4 7
75
73
1 7
42
4 5
53
51
2 4 3 1 5 7
2 3 1 4 5 7
2 1 3 4 5 7
1 2 3 4 5 7
42
3 4
41
32
1 3
21
(1)
(2)
(3)
(4)
(5)
13
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BubbleSort: pseudocodice
14
Algoritmo: bubbleSort(array S di dimensione n)
boolean scambi = false;
for(int i = 0; i < n; i++){
scambi = false;
//Confronto tra loro tutte le coppie tra n-i fino
//all’inizio dell’array. Dati due elementi, se non sono
//ordinati allora scambio la loro posizione
for(int j = 1; j < n-i; j++){
if(S[j-1] > S[j]) then {
swap(S, j-1, j);
scambi = true;
}
}
if(not scambi) then break;
}
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BubbleSort: analisi
Dato che dopo la k-esima scansione, i k elementi più
grandi sono correttamente ordinati, effettueremo al più
(n-1) cicli. Nel caso peggiore, alla k-esima scansione
vengono eseguito (n-k) confronti. Pertanto:
usando il cambiamento di variabile j = n-i e la serie
aritmetica (vedere Paragrafo 17.2 in Appendice al libro).
15
k=1
n-1
O(n-k) j=1
n-1
j= ( O ) = O(n2)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
O(n2) non è un buon risultato: stiamo facendo
tutti i confronti possibili!
Possiamo fare di meglio?
16
• Utilizza lo stesso approccio incrementale utilizzato nel selectionSort, ma
esegue nel caso peggiore un numero inferiore di confronti grazie all’uso di
una struttura dati che individua l’elemento più grande in tempo O(log n).
• NOTA: eseguiamo l’ordinamento a partire dall’elemento più grande (a
differenza del selectionSort dove cominciavamo dall’elemento più piccolo).
• Struttura dati heap: associata ad un insieme S di elementi è un albero
binario con le seguenti proprietà:
1) È completo fino al penultimo livello (un albero è completo se tutte le
foglie sono allo stesso livello)
2) gli elementi di S sono memorizzati nei nodi dell’albero. Ogni nodo v
contiene un solo elemento di S che indichiamo con chiave(v).
3) Vale sa seguente regola: il valore dell’elemento in un nodo è sempre
maggiore o uguale al valore degli elementi dei suoi figli.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
HeapSort
17
Se dato un nodo v, denotiamo rispettivamente con sin(v)
e des(v) il figlio sinistro e destro del nodo v, possiamo
sintetizzare la proprietà 3) di un Heap nel seguente
modo:
chiave(v) ≥ chiave(sin(v))
chiave(v) ≥ chiave(des(v))
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
HeapSort: proprietà di ordinamento
18
Rappresentazione ad albero e con vettore posizionale
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Struttura dati heap
37
22 31
14251513
37 912
37 22 31 13 15 25 14 7 3 12 9
vettore posizionale
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
sin(i) = 2i
des(i) = 2i+1
19
Le foglie nell’ultimo livello sono compattate a sinistra
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Heap con struttura rafforzata
37
22 31
14251513
37 912
37 22 31 13 15 25 14 7 3 12 9
vettore posizionale
0 1 2 3 4 5 6 7 8 9 10 11
Il vettore
posizionale ha
esattamente
dimensione n
20
1) Il massimo è contenuto nella radice
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Proprietà salienti degli heap
2) L’albero ha altezza O(log n)
3) Gli heap con struttura rafforzata possono essere
rappresentati in un array di dimensione pari a n
21
Algoritmo fixHeap(nodo v, heap H)
if (v è una foglia) then return
else
sia u il figlio di v con chiave massima
if ( chiave(v) < chiave(u) ) then
scambia chiave(v) e chiave(u)
fixHeap(u,H)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
La procedura fixHeap
Se tutti i nodi di H tranne v soddisfano la proprietà di
ordinamento a heap, possiamo ripristinarla come segue:
Tempo di esecuzione: O(log n)
22
Dato un heap H vogliamo individuare il massimo valore in esso contenuto e
rimuoverlo da H. Come fare?
• Sappiamo che il massimo è sempre contenuto nella radice!
• Con quale valore devo però sostituire il valore nella radice affinché la
proprietà di ordinamento dell’heap sia ancora valida?
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Estrazione del massimo
Tempo di esecuzione: O(log n)
23
getMax(heap H) elem e
1. elem e chiave(radice di H);
2. copio nella radice la chiave contenuta nella la foglia più a
destra dell’ultimo livello;
3. rimuovo la foglia;
4. ripristino la proprietà di ordinamento dell’heap richiamando
fixHeap sulla radice;
5. return e;
Algoritmo heapify(albero H)
if (H è vuoto) then return
else
heapify(sottoalbero sinistro di H)
heapify(sottoalbero destro di H)
fixHeap(radice di H, H)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Costruzione dell’heap
Costruisco un albero binario usando gli elementi del
vettore S e poi lo ordino usando il seguente algoritmo
ricorsivo basato sul divide et impera.
Tempo di esecuzione: T(n)= 2T(n/2) + O(log n)
T(n) = O(n) dal Teorema Master
24
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
L’algoritmo HeapSort
ordina in tempo O(n log n)
25
Algoritmo heapSort(array S di dimensione n)
if (S è vuoto) then return S;
else {
- costruisci un albero binario H con gli elementi di S;
- ordinalo usando heapyfy(H);//costa O(n)
- crea un coda C vuota.
- while(H non è vuoto){ //cicla n volte
C.enqueue(getMax(H)); //getMax ha costo O(log n)
- copia gli elementi di C in S nel giusto ordine
- return S
}
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
HeapSort: esempio di esecuzione
37 31 22 13 15 25
37
31
251513
22
22
15 13
22 15 13 25 31 37
(1)
(4)
31
25
1513
22
31 25 22 13 15 37
15
13
15 13 22 25 31 37
(2)
(5)
25
15
13
22
25 15 22 13 31 37
13
13 15 22 25 31 37
(3)
(6)
26
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 27
• Basato sulla tecnica divide et impera:
• Vediamo prima il passo Impera: dati due array ordinati A e
B fonderli a creare un nuovo array ordinato:
merge(array A ordinato, array B ordinato) array X ordinato
1. Sia X un nuovo array vuoto;
2. estrai ripetutamente il minimo di A e B e copialo in X, finché A
oppure B non diventa vuoto;
3. copia gli elementi dell’array non vuoto alla fine di X;
4. Restituisci X;
MergeSort (1/2)
La procedura merge(A,B) esegue al più |A| + |B| +1 confronti
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 28
MergeSort (2/2)
Algoritmo mergeSort(array S) array
if (S è vuoto) then return S;
else { if(|S| = 1) then return S
else {
S1 mergeSort(metà sinistra di S)
S2 mergeSort(metà destra di S)
return merge(S1, S2)
}
}
Passo divide: sappiamo come fondere due array ordinati,
quindi possiamo dividere l’array in due parti, ordinarli
ricorsivamente e poi fonderli nuovamente.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 29
MergeSort: esempio di esecuzione
4
3
6
2
6
4
3
2
4
3
2
6
3
4
6
2
2
3
4
6
divide divide merge merge
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 30
• Il numero di confronti del MergeSort è descritto dalla
seguente relazione di ricorrenza:
T(n) = T(n/2) + O(n)
• Usando il Teorema Master si ottiene:
T(n) = O(n log n)
(stesso costo dell’HeapSort!)
Tempo di esecuzione
Anche il QuickSort adotta la tecnica del divide et impera:
Sia A un array:
1 Divide: scegli un elemento x di A (chiameremo x perno) e partiziona gli
elementi di A in due sotto-array in cui il primo contiene tutti gli elementi
di A più piccoli o uguali ad x, ed il secondo tutti gli elementi di A
strettamente maggiori di x.
2 Risolvi i due sottoproblemi ricorsivamente.
3 Impera: restituisci la concatenazione dei due sotto-array ordinati
A differenza del MergeSort il passo divide è complesso, mentre il passo
impera (che qui consiste nella semplice fusione di due array) è molto
semplice
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
QuickSort
31
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 32
QuickSort: pseudocodice
Algoritmo quickSort(array A)
scegli un elemento x di A;
Partizione A rispetto ad x calcolando i due array:
A1 = { y A : y ≤ x }
A2 = { y A : y > x }
if (|A1| > 1) then quickSort(A1);
if (|A2| > 1) then quickSort(A2);
copia la concatenazione di A1 e A2 in A
Calcolare le due partizioni richiede O(n) confronti
• Nel caso peggiore, il perno scelto ad ogni passo è il
minimo o il massimo degli elementi nell’array.
• Il numero di confronti nel caso peggiore è descritto
dalla seguente relazione di ricorrenza:
C(n)=C(n-1) + O(n)
• Svolgendo per iterazione si ottiene
C(n) = O(n2)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
QuickSort: analisi nel caso peggiore
33
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
QuickSort: randomizzazione
• Possiamo evitare il caso peggiore scegliendo come
perno un elemento dell’array A "a caso".
• Poiché ogni elemento ha la stessa probabilità, pari a
1/n, di essere scelto come perno, il numero di
confronti nel caso atteso è:
a=0
n-1
C(n)= n-1+C(a)+C(n-a-1)1n
a=0
n-1
= n-1+ C(a)2n
dove a e (n-a-1) sono le dimensioni dei sottoproblemi
risolti ricorsivamente
34
La relazione di ricorrenza:
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
QuickSort: analisi nel caso medio
a=0
n-1
C(n)= n-1+ C(a)2n
ha soluzione C(n) ≤ 2 n log n, pertanto il numero di confronti
atteso è O(n log n)
Quindi il quickSort è meno efficiente nel caso peggiore del
mergeSort e del heapSort e per evitare il caso peggiore lo
rendiamo "randomizzato".
Il quickSort è però molto utilizzato in quanto esistono sue
varianti ottimizzate estremamente veloci.
35
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 36
Utilizzando algoritmi come il mergeSort e l'heapSort
possiamo ordinare un insieme di elementi con un numero
di confronti pari a O(n log n).
Possiamo fare di meglio?
• Dimostrazione (matematica) che non possiamo andare
più veloci di una certa quantità.
• Più precisamente, ogni algoritmo all’interno di un
certo modello di calcolo deve avere tempo di
esecuzione almeno pari a quella quantità.
• Non significa necessariamente che non è possibile fare
di meglio, infatti potrebbe essere possibile fare di
meglio al di fuori di quel modello di calcolo.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Lower bound
37
• Delimitazione inferiore: quantità di risorsa necessaria
per risolvere un determinato problema.
• Dimostrare che Ω(n log n) è lower bound al numero
di confronti richiesti per ordinare n oggetti.
Come?
Dobbiamo dimostrare che tutti gli algoritmi richiedono
almeno Ω(n log n) confronti!
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Lower bound per l'ordinamento
38
• In questo modello, per ordinare è possibile usare solo
confronti tra oggetti
• Primitive quali operazioni aritmetiche (somme o
prodotti), logiche (and e or), o altro (shift) sono
proibite.
• Sufficientemente generale per catturare le proprietà
degli algoritmi più noti
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Modello basato sui confronti
39
• Consideriamo un qualsiasi algoritmo A, che ordina
solo mediante confronti.
• Non abbiamo assolutamente idea di come funziona A!
• Ciò nonostante, dimostreremo che A deve eseguire
almeno Ω(n log n) confronti per ordinare un insieme
di elementi con cardinalità n.
• Dato che l’unica ipotesi su A è che ordini mediante
confronti, il lower bound sarà valido per tutti gli
algoritmi basati su confronti!
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Come dimostrare il lower bound
40
• Osservazione fondamentale: tutti gli algoritmi devono
confrontare elementi
• Dati due valori v1 e v2, i casi possibili sono tre:
v1 < v2 , v2 > v1 , oppure v1 = v2.
• Per semplicità assumeremo che tutti gli elementi sono
tra loro diversi
• Si assume dunque che tutti i confronti abbiano la
forma v1 < v2 , e il risultato del confronto sia vero o
falso
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Come dimostrare il lower bound
41
• Un albero di decisione rappresenta i confronti eseguiti da un algoritmo su un
dato input
• Il seguente esempio indica l'albero di decisione sull'insieme {v1,v2,v3}
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Alberi di decisione (1/3)
42
v1:v2
v2:v3 v1:v3
v1:v3 v2:v3v1,v2,v3 V2,v1,v3
v1,v3,v2 v3,v1,v2 v2,v3,v1 v3,v2,v1
< >
<
<
<
<
> >
> >
• Dato un insieme di n valori, sono possibili n! permutazioni (possibili
ordinamenti) l'albero di decisione deve quindi avere n! foglie.
• L'esecuzione di un algoritmo A corrisponde ad un cammino sull'albero di
decisione corrispondente all'input dato.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Alberi di decisione (2/3)
43
v1:v2
v2:v3 v1:v2
v1:v3 v1:v2v1,v2,v3 V2,v1,v3
v1,v3,v2 v2,v1,v2 v2,v3,v1 v3,v2,v1
< >
<
<
<
<
> >
> >
• Riassumendo:
– Albero binario;
– Deve contenere n! foglie
– Il cammino da una radice ad una foglia
rappresenta l'esecuzione dell'algoritmo su
un'istanza.
• Il più lungo cammino dalla radice ad una
foglia rappresenta il numero di confronti che
l'algoritmo deve eseguire nel caso peggiore.
Alberi di decisione (2/4)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 44
• Teorema: qualunque albero di decisione che
ordina n elementi ha altezza W(n log n)
• Corollario: nessun algoritmo di ordinamento
basato sui confronti ha complessità migliore di
W(n log n)
Il lower bound W(n logn)
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 45
• Un albero di decisione è binario;
• Un albero binario di altezza h non ha più di 2h-1 foglie
• Il nostro albero deve avere almeno n! foglie, quindi:
– 2h-1 ≥ n! h-1 ≥ log(n!)
– n! ≥ (n/e)n (approssimazione di Stirling)
– h-1 ≥ log(n!) ≥ log(n/e)n = n log(n) – n log(e) =
W(n log n)
Dimostrazione del teorema
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008 46
• Un importante corollario del teorema che fissa W(n log
n) come lower bound per il problema dell'ordinamento
nel modello basato sui confronti è che gli algoritmi
heapSort e mergeSort sono algoritmi ottimi (con
complessità asintotica ottima).
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Quindi?
47
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Ordinamenti lineari
(per dati di input con proprietà particolari)
48
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Ordinamento di n interi in [1,n]
Abbiano n interi distinti con valore compreso
nell'intervallo [1,n]
In quanto tempo possiamo ordinarli?
• O(1) l'unico ordinamento possibile è
{1,2,3,4,5,6,…,n}
• Contraddice il lower bound?
• No! Perché?
49
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Ordinamento di n interi in [1,n]
Abbiano n interi distinti con valore compreso
nell'intervallo [1,n]
In quanto tempo possiamo ordinarli?
• O(1) l'unico ordinamento possibile è
{1,2,3,4,5,6,…,n}
• Contraddice il lower bound?
• No! Perché? Siamo fuori dal modello
basato sui confronti
50
Nuovo problema, meno banale:
"ordinare n interi con valori in [1,k]"
Strategia: mantiene un array Y di k contatori tale che
Y[x] = numero di volte che il valore x compare nell’array
di input X
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
IntegerSort: fase 1
51
• ESEMPIO:
array X di 5 interi compresi tra 1 e 8
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
IntegerSort: fase 1
(a) Calcolo di Y
X
Y 0 00 0 1 0 00
5 6861
1 2 3 4 5 6 7 8
1 00 0 1 0 11
5 6861
1 2 3 4 5 6 7 8
X
Y
1 00 0 1 0 00
5 6861
1 2 3 4 5 6 7 8
5 686
1 00 0 1 0 12
1
1 2 3 4 5 6 7 8
1 00 0 1 0 01
5 6861
1 2 3 4 5 6 7 8
52
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
IntegerSort: fase 2
(b) Ricostruzione di X
X
Y 1 00 0 1 0 12
1
1 2 3 4 5 6 7 8
X
Y 0 00 0 0 0 12
51 6 6
1 2 3 4 5 6 7 8
0 00 0 1 0 12
1
1 2 3 4 5 6 7 8
0 00 0 0 0 10
51 6 6
1 2 3 4 5 6 7 8
0 00 0 1 0 12
1 5
1 2 3 4 5 6 7 8
0 00 0 0 0 10
1 5 8
1 2 3 4 5 6 7 8
6 6
Dopo aver contato quanto volte si ripete ogni elemento
in X, scorriamo Y da sinistra verso destra e, se Y[x]=k,
scriviamo in X il valore x per k volte
53
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
IntegerSort: pseudocodice
54
Algoritmo integerSort(intero k, array X di dimensione n)
Sia Y un array di dimensione k;
//inizializzo tutte le celle di Y a 0;
for(int i 0; i < k; i++) { Y[i] 0; }
//scandisco X ed ogni volta che X contiene un valore p
//incremento di uno il valore in Y[p]
for(int h 0; h < n; h++) { Y[X[h]] Y[X[h]] + 1; }
j 1;
//scandisco Y, se Y[t]=k con k > 0, scrivo in X
//il valore t per k volte
for( t 0; t < k; t++ ) {
while( Y[t] > 0 ){
X[j] t; j++; Y[t] Y[t]-1;
}
}
L'algoritmo IntegerSort richiede:
– Tempo O(k) per inizializzare Y (creo Y e inizializzo ogni sua cella a 0)
– Tempo O(n) per scandire X (contare i sui valori e incrementare i contatori
in Y)
– Tempo O(n+k) per ricostruire X (scandire Y e riscrivere gli n valori in X)
Quindi integerSort richiede un tempo pari a O(n+k). Questo significa
che, finché k è proporzionale con n ( k = O(n)), il costo di
integerSort è lineare con n ( O(n) ). Questa proprietà di perde se si
possono avere valori di k molto grandi.
Es. per k = n5 il costo di integerSort sarà O(n + n5) = O(n5).
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
IntegerSort: analisi
55
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BucketSort
E se invece di interi vogliamo ordinare altri tipi di elementi (esempio
le persone in una lista in base al loro mese di nascita)?
Per ordinare n record con chiavi intere in [1,k]
• Basta mantenere un array di liste, anziché di contatori, ed operare
come per IntegerSort
• La lista Y[x] conterrà gli elementi con chiave uguale a x
• Per ottenere una lista ordinata vado poi a concatenare le liste in Y
• Tempo O(n+k) come per IntegerSort
56
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
BucketSort: esempio
• Ho una lista di 1000 record contenenti le seguenti informazioni
sulle persone:
– Nome; Cognome; Data di nascita (gg/mm/aaaa)
• Ordinare i record sulla base del mese di nascita delle persone
• Ci sono solo 12 mesi quindi userò un array di liste con 12 caselle
57
12
101112
{Nome, Cognome,Data}
• Un algoritmo è stabile se preserva l’ordine iniziale
tra elementi con la stessa chiave
• Il BucketSort può essere reso stabile appendendo
gli elementi di X in coda alla opportuna lista Y[i]
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
Stabilità
58
Come abbiamo visto l'BucketSort funziona bene quando k è
dello stesso ordine di n. Che fare quando k è molto grande?
• Rappresentiamo gli elementi in base b (binario, decimale.
esadecimale, ecc.), ed eseguiamo una serie di BucketSort
• Partiamo ordinando i numero usando come chiave la cifra
meno significativa e poi ci spostiamo verso quella più
significativa.
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
RadixSort
2397
4368
5924
5924
2397
4368
5924
4368
2397
4368
2397
5924
2397
4368
5924
Per
b=10
59
• Se x e y hanno una diversa t-esima cifra, la t-esima passata
di BucketSort li ordina
• Se x e y hanno la stessa t-esima cifra, la proprietà di
stabilità del BucketSort li mantiene ordinati correttamente
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
RadixSort: correttezza
Dopo la t-esima passata di BucketSort, i
numeri sono correttamente ordinati rispetto
alle t cifre meno significative
60
Algoritmi e Strutture Dati - Domenico Fabio Savo da Demetrescu et al. The McGraw - Hill, 2008
RadixSort: tempo di esecuzione
61
Se usiamo come base per il bucketSort un valore
b = Q(n), l'algoritmo radixSort ordina n numeri
interi compresi tra [1,k], in tempo: