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