150 likes | 471 Views
Radix Sort (Chapter 10). Comparison sorting has runtime Q (n log n). Can we do better? To do better, we must use more information from the key. Look at the bits . Radix sort: treat the keys as radix-R (i.e. base-R) numbers. Sorting Zip Codes.
E N D
Radix Sort (Chapter 10) • Comparison sorting has runtime Q(n log n). • Can we do better? • To do better, we must use more information from the key. • Look at the bits. • Radix sort: treat the keys as radix-R (i.e. base-R) numbers.
Sorting Zip Codes • How would you sort a set of integers in the range 0..9 in O(n) time? • use 10 buckets (linked lists) to accumulate the items. • How would you sort a set of zip codes in O(n) time? • use 10 buckets to accumulate items • sort once for digit 5 (least significant), then 4, then 3, then 2, then 1. (LSD sort) • note that each stage must be stable • (you can sort from left to right (MSD) if you are clever.) • Sorting machines for punched cards…
Radix Sort Utilities • We need to be able to get a chunk out of a key. inline int digit(int a, int digit, int radix){ return (a / pow(radix,digit)) % radix; } • It could be a fixed number of bits–often that’s fastest. const int bitsword = 32; bitschunk = 4; const int chunksword = bitsword/bitschunk; const int radix = 1 << bitschunk; inline int digit(long a, int b) { return (a >> bitschunk*(chunksword-b-1)) & (radix-1); }
Binary Quicksort • How about using bits as pivots for quicksort? • move all numbers starting with bit 0 before those starting with bit 1 (like a Quicksort partition on 10000…) • recursively sort each half on bit 2, each quarter on bit 3, …
Binary Quicksort: Runtime? • b passes, where b is the number of bits per word • O(n) time per pass • O(b n) = O(n) worst case • but in practice it’s worse than quicksort – high constant. • actually, you may not even have to look at all the input bits! • but what happens if we sort many small number?
MSD Radix Sort • Like binary quicksort – but with larger chunk size • But how can we move items intothe correct place in one pass? • Need to count the number of items starting with a, b, c, etc. • Then we can move items into place in one pass. • (Hmmm, let’s see…the place for the first c word will be after all the a and b words…)
MSD Radix Sort – code #define bin(A) 1+count[A] template <class Item> void radixMSD(Item a[], int l, int r, int d) { int i, j, count[R+1]; static Item aux[maxN] if (d > bytesword) return; if (r-1 <= M) {insertion(a, l, r); return; } for (j=0; j<R; j++) count[j] = 0; for (i=l; i<=r; i++) count[digit(a[i],d)+1]++; for (j=1; j<R; j++) count[j] += count[j-1]; for (int i=l; i<=r; i++) aux[count[digit(a[i],d)]++] = a[i]; for (i=l; i<=r; i++) a[i] = aux[i-l]; radixMSD(a, l, bin(0)-1, d+1); for (j=0; j<R-1; j++) radixMSD(a, bin(j), bin(j+1)-1, d+1); }
LSD Binary • If we work from right to left – what changes? • Just do a stable pass for each bit!
LSD Radix Sort • Like LSD Binary sort – but on bigger chunks of the key. • We still need to count the number of each type to figure out where to move items in one pass • Runtime is still O(n).
LSD Radix Sort -- code template <class Item> void radixLSD(Item a[], int l, int r) { static Item aux[maxN]; for (int d = bytesword-1; d>=0; d--) { int i, j, count[R+1]; for (j=0; j<R; j++) count[j] = 0; for (i=l; i<=r; i++) count[digit(a[i],d)+1]++; for (j=1; j<R; j++) cout[j] += count[j-1]; for (i=l; i<=r; i++) aux[count[digit(a[i],d)]++] = a[i]; for (i=l; i<=r; i++) a[i] = aux[i-l]; } }
Empirical Results • Radix sort can be fastest, if used with care • E.g. sorting random files of N 32-bit ints, with cutoff to insertion sort for N<16: 4-bit 8-bit N Q M L M L L* 25000 5 14 21 29 8 4 100000 21 77 92 47 39 18 400000 102 278 377 581 169 88 Q = standard quicksort M = MSD radix sort L = LSD radix sort L* = LSD radix sort on MSD half of the bits