Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8039 | hidnplayr | 1 | /******************************************************************************* |
2 | * |
||
3 | * Author: Remi Dufour - remi.dufour@gmail.com |
||
4 | * Date: July 23rd, 2012 |
||
5 | * |
||
6 | * Name: Quicksort |
||
7 | * |
||
8 | * Description: This is a well-known sorting algorithm developed by C. A. R. |
||
9 | * Hoare. It is a comparison sort and in this implementation, |
||
10 | * is not a stable sort. |
||
11 | * |
||
12 | * Note: This is public-domain C implementation written from |
||
13 | * scratch. Use it at your own risk. |
||
14 | * |
||
15 | *******************************************************************************/ |
||
16 | |||
17 | #include |
||
18 | #include |
||
19 | |||
20 | /* Insertion sort threshold shift |
||
21 | * |
||
22 | * This macro defines the threshold shift (power of 2) at which the insertion |
||
23 | * sort algorithm replaces the Quicksort. A zero threshold shift disables the |
||
24 | * insertion sort completely. |
||
25 | * |
||
26 | * The value is optimized for Linux and MacOS on the Intel x86 platform. |
||
27 | */ |
||
28 | #ifndef INSERTION_SORT_THRESHOLD_SHIFT |
||
29 | # ifdef __APPLE__ & __MACH__ |
||
30 | # define INSERTION_SORT_THRESHOLD_SHIFT 0 |
||
31 | # else |
||
32 | # define INSERTION_SORT_THRESHOLD_SHIFT 2 |
||
33 | # endif |
||
34 | #endif |
||
35 | |||
36 | /* Macro SWAP |
||
37 | * |
||
38 | * Swaps the elements of two arrays. |
||
39 | * |
||
40 | * The length of the swap is determined by the value of "SIZE". While both |
||
41 | * arrays can't overlap, the case in which both pointers are the same works. |
||
42 | */ |
||
43 | #define SWAP(A,B,SIZE) \ |
||
44 | { \ |
||
45 | register char *a_byte = A; \ |
||
46 | register char *b_byte = B; \ |
||
47 | register const char *a_end = a_byte + SIZE; \ |
||
48 | \ |
||
49 | while (a_byte < a_end) \ |
||
50 | { \ |
||
51 | register const char swap_byte = *b_byte; \ |
||
52 | *b_byte++ = *a_byte; \ |
||
53 | *a_byte++ = swap_byte; \ |
||
54 | } \ |
||
55 | } |
||
56 | |||
57 | /* Macro SWAP_NEXT |
||
58 | * |
||
59 | * Swaps the elements of an array with its next value. |
||
60 | * |
||
61 | * The length of the swap is determined by the value of "SIZE". This macro |
||
62 | * must be used at the beginning of a scope and "A" shouldn't be an expression. |
||
63 | */ |
||
64 | #define SWAP_NEXT(A,SIZE) \ |
||
65 | register char *a_byte = A; \ |
||
66 | register const char *a_end = A + SIZE; \ |
||
67 | \ |
||
68 | while (a_byte < a_end) \ |
||
69 | { \ |
||
70 | register const char swap_byte = *(a_byte + SIZE); \ |
||
71 | *(a_byte + SIZE) = *a_byte; \ |
||
72 | *a_byte++ = swap_byte; \ |
||
73 | } |
||
74 | |||
75 | /* Function Quicksort |
||
76 | * |
||
77 | * This function performs a basic Quicksort. This implementation is the |
||
78 | * in-place version of the algorithm and is done in he following way: |
||
79 | * |
||
80 | * 1. In the middle of the array, we determine a pivot that we temporarily swap |
||
81 | * to the end. |
||
82 | * 2. From the beginning to the end of the array, we swap any elements smaller |
||
83 | * than this pivot to the start, adjacent to other elements that were |
||
84 | * already moved. |
||
85 | * 3. We swap the pivot next to these smaller elements. |
||
86 | * 4. For both sub-arrays on sides of the pivot, we repeat this process |
||
87 | * recursively. |
||
88 | * 5. For a sub-array smaller than a certain threshold, the insertion sort |
||
89 | * algorithm takes over. |
||
90 | * |
||
91 | * As an optimization, rather than performing a real recursion, we keep a |
||
92 | * global stack to track boundaries for each recursion level. |
||
93 | * |
||
94 | * To ensure that at most O(log2 N) space is used, we recurse into the smaller |
||
95 | * partition first. The log2 of the highest unsigned value of an integer type |
||
96 | * is the number of bits needed to store that integer. |
||
97 | */ |
||
98 | void qsort(void *array, |
||
99 | size_t length, |
||
100 | size_t size, |
||
101 | int(*compare)(const void *, const void *)) |
||
102 | { |
||
103 | /* Recursive stacks for array boundaries (both inclusive) */ |
||
104 | struct stackframe |
||
105 | { |
||
106 | void *left; |
||
107 | void *right; |
||
108 | } stack[CHAR_BIT * sizeof(void *)]; |
||
109 | |||
110 | /* Recursion level */ |
||
111 | struct stackframe *recursion = stack; |
||
112 | |||
113 | #if INSERTION_SORT_THRESHOLD_SHIFT != 0 |
||
114 | /* Insertion sort threshold */ |
||
115 | const int threshold = size << INSERTION_SORT_THRESHOLD_SHIFT; |
||
116 | #endif |
||
117 | |||
118 | /* Assign the first recursion level of the sorting */ |
||
119 | recursion->left = array; |
||
120 | recursion->right = (char *)array + size * (length - 1); |
||
121 | |||
122 | do |
||
123 | { |
||
124 | /* Partition the array */ |
||
125 | register char *index = recursion->left; |
||
126 | register char *right = recursion->right; |
||
127 | char *left = index; |
||
128 | |||
129 | /* Assigning store to the left */ |
||
130 | register char *store = index; |
||
131 | |||
132 | /* Pop the stack */ |
||
133 | --recursion; |
||
134 | |||
135 | /* Determine a pivot (in the middle) and move it to the end */ |
||
136 | const size_t middle = (right - left) >> 1; |
||
137 | SWAP(left + middle - middle % size,right,size) |
||
138 | |||
139 | /* From left to right */ |
||
140 | while (index < right) |
||
141 | { |
||
142 | /* If item is smaller than pivot */ |
||
143 | if (compare(right, index) > 0) |
||
144 | { |
||
145 | /* Swap item and store */ |
||
146 | SWAP(index,store,size) |
||
147 | |||
148 | /* We increment store */ |
||
149 | store += size; |
||
150 | } |
||
151 | |||
152 | index += size; |
||
153 | } |
||
154 | |||
155 | /* Move the pivot to its final place */ |
||
156 | SWAP(right,store,size) |
||
157 | |||
158 | /* Performs a recursion to the left */ |
||
159 | #define RECURSE_LEFT \ |
||
160 | if (left < store - size) \ |
||
161 | { \ |
||
162 | (++recursion)->left = left; \ |
||
163 | recursion->right = store - size; \ |
||
164 | } |
||
165 | |||
166 | /* Performs a recursion to the right */ |
||
167 | #define RECURSE_RIGHT \ |
||
168 | if (store + size < right) \ |
||
169 | { \ |
||
170 | (++recursion)->left = store + size; \ |
||
171 | recursion->right = right; \ |
||
172 | } |
||
173 | |||
174 | /* Insertion sort inner-loop */ |
||
175 | #define INSERTION_SORT_LOOP(LEFT) \ |
||
176 | { \ |
||
177 | register char *trail = index - size; \ |
||
178 | while (trail >= LEFT && compare(trail, trail + size) > 0) \ |
||
179 | { \ |
||
180 | SWAP_NEXT(trail,size) \ |
||
181 | trail -= size; \ |
||
182 | } \ |
||
183 | } |
||
184 | |||
185 | /* Performs insertion sort left of the pivot */ |
||
186 | #define INSERTION_SORT_LEFT \ |
||
187 | for (index = left + size; index < store; index +=size) \ |
||
188 | INSERTION_SORT_LOOP(left) |
||
189 | |||
190 | /* Performs insertion sort right of the pivot */ |
||
191 | #define INSERTION_SORT_RIGHT \ |
||
192 | for (index = store + (size << 1); index <= right; index +=size) \ |
||
193 | INSERTION_SORT_LOOP(store + size) |
||
194 | |||
195 | /* Sorts to the left */ |
||
196 | #if INSERTION_SORT_THRESHOLD_SHIFT == 0 |
||
197 | # define SORT_LEFT RECURSE_LEFT |
||
198 | #else |
||
199 | # define SORT_LEFT \ |
||
200 | if (store - left <= threshold) \ |
||
201 | { \ |
||
202 | INSERTION_SORT_LEFT \ |
||
203 | } \ |
||
204 | else \ |
||
205 | { \ |
||
206 | RECURSE_LEFT \ |
||
207 | } |
||
208 | #endif |
||
209 | |||
210 | /* Sorts to the right */ |
||
211 | #if INSERTION_SORT_THRESHOLD_SHIFT == 0 |
||
212 | # define SORT_RIGHT RECURSE_RIGHT |
||
213 | #else |
||
214 | # define SORT_RIGHT \ |
||
215 | if (right - store <= threshold) \ |
||
216 | { \ |
||
217 | INSERTION_SORT_RIGHT \ |
||
218 | } \ |
||
219 | else \ |
||
220 | { \ |
||
221 | RECURSE_RIGHT \ |
||
222 | } |
||
223 | #endif |
||
224 | |||
225 | /* Recurse into the smaller partition first */ |
||
226 | if (store - left < right - store) |
||
227 | { |
||
228 | /* Left side is smaller */ |
||
229 | SORT_RIGHT |
||
230 | SORT_LEFT |
||
231 | |||
232 | continue; |
||
233 | } |
||
234 | |||
235 | /* Right side is smaller */ |
||
236 | SORT_LEFT |
||
237 | SORT_RIGHT |
||
238 | |||
239 | #undef RECURSE_LEFT |
||
240 | #undef RECURSE_RIGHT |
||
241 | #undef INSERTION_SORT_LOOP |
||
242 | #undef INSERTION_SORT_LEFT |
||
243 | #undef INSERTION_SORT_RIGHT |
||
244 | #undef SORT_LEFT |
||
245 | #undef SORT_RIGHT |
||
246 | } |
||
247 | while (recursion >= stack); |
||
248 | } |
||
249 | |||
250 | #undef INSERTION_SORT_THRESHOLD_SHIFT |
||
251 | #undef SWAP |
||
252 | #undef SWAP_NEXT>=>=>=>><>>>>>><>>> |