Radix Sort

Transcript

Radix Sort
Laboratorio di Algoritmi e Strutture Dati
II Semestre 2005/2006
Radix Sorts
Marco Antoniotti
Ordinamenti non basati su confronti
• Per gli algoritmi di ordinamento basati su confronti di N elementi
esiste il limite inferiore Ω(N lg(N))
• È possibile ordinare N elementi in tempo minore sfruttando la
struttura delle chiavi da ordinare
• Variazioni
–
–
–
–
–
Radix sort
Counting Sort
Bucket Sort
MSD sort
Ecc. Ecc. Ecc.
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
1/22
1
Radix Sort
• Radix (radice) sort su stringhe
– Stessa idea per bits, cifre, ecc
– Ovvero, utile per tutte quelle “chiavi” che possono venir destrutturate in componenti più semplici
• Applicazioni
–
–
–
–
Ordinamento tra stringhe
Indicizzazione di testi
Controllo copiature e plagiarizzazioni
Biologia molecolare computazionale
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
2/22
Applicazione: controllo ridondanza
•
Sottostringa ripetuta più lunga
–
–
Data una stringa di N caratteri, trovare la sottostringa ripetuta più lunga
Esempio
a a c a a g t t t a c a a g c
–
•
Applicazione: biologia molecolare computazionale
Forza bruta e stupida
–
–
Si provano tutti gli indici i e j e tutte le possibili lunghezze k
Complessità O(W N3) dove W è la lunghezza del “match” più lungo, mentre N è la
lunghezza della stringa
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
3/22
2
Applicazione: controllo ridondanza
•
Sottostringa ripetuta più lunga
–
–
Data una stringa di N caratteri, trovare la sottostringa ripetuta più lunga
Esempio
a a c a a g t t t a c a a g c
–
•
Applicazione: biologia molecolare computazionale
Forza bruta meno stupida
–
–
Si provano tutti gli indici i e j per ogni inizio di un possibile “match”
Complessità O(W N2) dove W è la lunghezza del “match” più lungo, mentre N è la
lunghezza della stringa
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
4/22
Una soluzione basata
sull’ordinamento dei suffissi
•
Suffix sort
–
–
Si generano tutti i suffissi dell’input
Si ordinano i suffissi per avvicinare tutti “match” più lunghi
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
5/22
3
Problema: come ordinare
efficientemente tutte queste stringhe
• Notazione
–
–
–
–
Stringa = sequenza di lunghezza variabile di caratteri
W = massimo numero di caratteri per stringa
N = numero di stringhe in input
R = radice
• N.B. La radice è 256 per ASCII esteso, 65536 per l’UNICODE originale,
da 4 a 27 o poco più per gli standard di rappresentazione di sequenze
genomiche
• Sintassi C e C++
–
–
–
–
–
Array di stringhe: char* a[]; (Potremmo usare STL in C++)
Numero di stringhe: int N;
L’i-esima stringa: a[i];
Il d-esimo carattere della stringa i-esima: a[i][d];
Le stringa da ordinare: a[0] … a[N-1]
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
6/22
Codice per risolvere il problema
• In C
#define N /* some number */
char * s = read_string(stdin, N);
char ** suffixes = malloc(N * sizeof(char *));
int i;
for (i = 0; i < N; i++)
suffixes[i] = substring(s, i, N);
Quicksort di stringhe, per esempio
string_sort(suffixes);
fprintf(stdout, “%s\n”, lcp(suffixes));
Least common prefix di stringhe adiacenti
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
7/22
4
Prestazioni di string sort
• Il nostro algoritmo per l’ordinamento dei suffissi può assumere
le prestazioni di quicksort
• Quindi le prestazioni saranno
O(W N lg(N))
ovvero un miglioramento notevole
• Ciononostante si può - in questo caso - far meglio
– Idea: key indexing counting come passo base
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
8/22
Key Indexing Counting (primo passo)
• Si contano le frequenze di ogni lettera (in posizione 0)
int *count = (int*) malloc(sizeof(int) * (256+1));
int i;
for (i = 0; i < N; i++) {
char c = a[i][d];
count[c + 1]++;
}
d = 0 in quest’esempio
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
9/22
5
Key Indexing Counting (secondo passo)
•
•
Si contano le frequenze di ogni lettera (in posizione 0)
Si computanto le frequenze cumulative
for (i = 0; i < 256; i++) {
count[i] += count[i - 1];
}
Frequenze cumulative
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
10/22
Key Indexing Counting (terzo passo)
•
•
•
Si contano le frequenze di ogni lettera (in posizione 0)
Si computanto le frequenze cumulative
Si riarrangiano le string sulla base delle frequenze cumulative
char ** temp; /* N puntatori */
for (i = 0; i < N; i++) {
char c = a[i][d];
temp[count[c]++] = a[i];
}
Riarrangiamento
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
11/22
6
Key Indexing Counting (quarto passo)
•
•
•
•
Si contano le frequenze di ogni lettera (in posizione 0)
Si computanto le frequenze cumulative
Si riarrangiano le string sulla base delle frequenze cumulative
Si ricopia su ‘a’ l’array ‘temp’
for (i = 0; i < N; i++) {
a[i] = temp[i];
}
Ri-copia
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
12/22
LSD Radix Sort
• Least significant digit radix sort
Un metodo di ordinamento molto antico
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
13/22
7
LSD Radix Sort
•
Consideriamo i caratteri o cifre (digits) di ogni elemento da destra
(meno significativo) a sinistra (più significativo)
Si usi il metodo di “key indexing” per ordinare stabilmente ogni
elemento
•
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
14/22
LSD Radix Sort
•
Consideriamo i caratteri o cifre (digits) di ogni elemento da destra (meno
significativo) a sinistra (più significativo)
Si usi il metodo di “key indexing” per ordinare stabilmente ogni elemento
•
void sorting_lsd(char * a[], int N, int W) {
int d;
for (d = W - 1; d >= 0; d--) {
/* key-indexing count sort su tutti i caratteri ‘d’. */
}
}
Si assumono N stringhe di lunghezza fissa W
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
15/22
8
LSD Radix Sort: prestazioni
•
LSD radix sort ha la seguente complessità
Θ(W(N + R))
•
Domanda: perchè non si sta violando il limite inferiore di Ω(N lg(N)) sugli ordinamenti?
•
Vantaggi
–
•
Svantaggi
–
–
–
–
–
•
È il metodo di ordinamento più veloce per insiemi di stringhe di lunghezza fissa (e.g. C.A.P. o C.F.)
Accesso alla memoria molto “casuale” (caching)
Ciclo interno molto complesso
Perde molto tempo sugli elementi meno significativi
Non funziona per stringhe di lunghezza variabile
Poco “ordine” fino all’ultimo passo
Obiettivo: trovare un algoritmo che funzioni bene per stringhe di lunghezza variabile
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
16/22
MSD Radix Sort
• Most Significant Digit radix sort
– Si partiziona l’input (e.g. N
stringhe) in W parti secondo il
primo elemento (carattere)
– Si ordina ricorsivamente ogni
stringa cha inizia con lo stesso
carattere (ecc. ecc.)
• Domanda: come si ordina
secondo il d-esimo carattere?
• Si usa key-indexing counting
sort
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
17/22
9
MSD Radix Sort
void sorting_msd(char * a[], int N, int W) {
msd(a, 0, N - 1, 0, W);
}
void msd(char * a[], int l, int r, int d, int W) {
int * count;
int i;
if (r <= l) return;
/* key-indexing counting sort sull’elemento ‘d’ da a[l] a a[r]. */
count = (int*) malloc(sizeof(int) * (256+1));
/* … */
/* Si ordinano ricorsivamente le 255 partizioni
* (Si assume che le ‘stringhe’ siano terminate da ‘\0’.
*/
for (i = 0; i < 255; i++)
msd(a, l + count[i], l + count[i + 1] - 1, d + 1, W);
}
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
18/22
MSD Radix Sort: analisi
• Complessità
– La complessità di MSD Radix Sort è
O(W(N + R))
come LSD
• Svantaggi
– Troppo lento per piccoli insiemi di elementi
• ASCII: 100x più lento di insertion sort per N = 2
• UNICODE: 30000x più lento di insertion sort per N = 2
– Enorme numero di chiamate ricorsive su piccoli insiemi
• Soluzione
– Si usa insertion sort su piccoli inputs
– Competitivo con soluzioni basate su quicksort
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
19/22
10
Struttura ricorsiva delle chiamate di
MSD Radix Sort
Struttura a “trie”: la struttura di MSD Radix Sort
Problema: l’algoritmo tocca un mucchio di nodi vuoti
⇒ L’albero può essere in realtà R volte più grande di quanto appaia
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
20/22
Corrispondenza tra “alberi” ed
algoritmi di ordinamento
•
•
I Binary Search Trees (BSTs) corrispondono alla struttura ricorsiva di quicksort
I “trie a R vie” corrispondono alla struttura ricorsiva di MSD Radix Sort
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
21/22
11
Conclusioni
• Gli algoritmi di ordinamento basati su confronti hanno un limite
teorico e pratico di Ω(N lg(N))
• Sfruttando la struttura delle chiavi su cui eseguire l’ordinamento
(stringhe e caratteri, numeri e cifre) è possibile battere questo
limite in alcuni casi
• L’operazione di key-counting sort è fondamentale
– Least Significant Digit Radix Sort
– Most Significant Digit Radix Sort
• Quicksort ha una struttura ricorsiva di chiamate corrispondente
a BSTs
• MSD ha una struttura ricorsiva di chiamate corrispondente ai
“tries ad R vie”
II Semestre 2005/2006
Laboratorio Algoritmi - Marco Antoniotti
22/22
12