1 #include <assert.h>
2 #include <limits.h>
3 #include <string.h>
4
5 #include "radixsort.h"
6
7 /* in-place MSB radix sort for null-terminated strings */
8
9 /* helper routine for swapping */
10 static void
11 swapStrings(const char **a, const char **b)
12 {
13 const char *temp;
14
15 temp = *a;
16 *a = *b;
17 *b = temp;
18 }
19
20 /* this is the internal routine that assumes all strings are equal for the
21 * first k characters */
22 static void
23 radixSortInternal(int n, const char **a, int k)
24 {
25 int i;
26 int count[UCHAR_MAX+1]; /* number of strings with given character in position k */
27 int mode; /* most common position-k character */
28 const char **bucket[UCHAR_MAX+1]; /* position of character block in output */
29 const char **top[UCHAR_MAX+1]; /* first unused index in this character block */
30
31 /* loop implements tail recursion on most common character */
32 while(n > 1) {
33
34 /* count occurrences of each character */
35 memset(count, 0, sizeof(int)*(UCHAR_MAX+1));
36
37 for(i = 0; i < n; i++) {
38 count[(unsigned char) a[i][k]]++;
39 }
40
41 /* find the most common nonzero character */
42 /* we will handle this specially */
43 mode = 1;
44 for(i = 2; i < UCHAR_MAX+1; i++) {
45 if(count[i] > count[mode]) {
46 mode = i;
47 }
48 }
49
50 if(count[mode] < n) {
51
52 /* generate bucket and top fields */
53 bucket[0] = top[0] = a;
54 for(i = 1; i < UCHAR_MAX+1; i++) {
55 top[i] = bucket[i] = bucket[i-1] + count[i-1];
56 }
57
58 /* reorder elements by k-th character */
59 /* this is similar to dutch flag algorithm */
60 /* we start at bottom character and swap values out until everything is in place */
61 /* invariant is that for all i, bucket[i] <= j < top[i] implies a[j][k] == i */
62 for(i = 0; i < UCHAR_MAX+1; i++) {
63 while(top[i] < bucket[i] + count[i]) {
64 if((unsigned char) top[i][0][k] == i) {
65 /* leave it in place, advance bucket */
66 top[i]++;
67 } else {
68 /* swap with top of appropriate block */
69 swapStrings(top[i], top[(unsigned char) top[i][0][k]]++);
70 }
71 }
72 }
73
74 /* we have now reordered everything */
75 /* recurse on all but 0 and mode */
76 for(i = 1; i < UCHAR_MAX+1; i++) {
77 if(i != mode) {
78 radixSortInternal(count[i], bucket[i], k+1);
79 }
80 }
81
82 /* tail recurse on mode */
83 n = count[mode];
84 a = bucket[mode];
85 k = k+1;
86
87 } else {
88
89 /* tail recurse on whole pile */
90 k = k+1;
91 }
92 }
93 }
94
95 void
96 radixSort(int n, const char **a)
97 {
98 radixSortInternal(n, a, 0);
99 }