Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1805 | yogev_ezra | 1 | static void shortsort(char *lo, char *hi, unsigned width, |
2 | int (*comp)(const void *, const void *)); |
||
3 | |||
4 | static void swap(char *p, char *q, unsigned width); |
||
5 | |||
6 | /* this parameter defines the cutoff between using quick sort and |
||
7 | insertion sort for arrays; arrays with lengths shorter or equal to the |
||
8 | below value use insertion sort */ |
||
9 | |||
10 | #define CUTOFF 8 /* testing shows that this is good value */ |
||
11 | |||
12 | #define STKSIZ (8*sizeof(void*) - 2) |
||
13 | |||
14 | /*** |
||
15 | *qsort(base, num, wid, comp) - quicksort function for sorting arrays |
||
16 | * |
||
17 | *Purpose: |
||
18 | * quicksort the array of elements |
||
19 | * side effects: sorts in place |
||
20 | * maximum array size is number of elements times size of elements, |
||
21 | * but is limited by the virtual address space of the processor |
||
22 | * |
||
23 | *Entry: |
||
24 | * char *base = pointer to base of array |
||
25 | * unsigned num = number of elements in the array |
||
26 | * unsigned width = width in bytes of each array element |
||
27 | * int (*comp)() = pointer to function returning analog of strcmp for |
||
28 | * strings, but supplied by user for comparing the array elements. |
||
29 | * it accepts 2 pointers to elements. |
||
30 | * Returns neg if 1<2, 0 if 1=2, pos if 1>2. |
||
31 | * |
||
32 | *Exit: |
||
33 | * returns void |
||
34 | * |
||
35 | *******************************************************************************/ |
||
36 | |||
37 | void qsort ( |
||
38 | void *base, |
||
39 | unsigned num, |
||
40 | unsigned width, |
||
41 | int (*comp)(const void *, const void *) |
||
42 | ) |
||
43 | { |
||
44 | /* Note: the number of stack entries required is no more than |
||
45 | 1 + log2(num), so 30 is sufficient for any array */ |
||
46 | char *lo, *hi; /* ends of sub-array currently sorting */ |
||
47 | char *mid; /* points to middle of subarray */ |
||
48 | char *loguy, *higuy; /* traveling pointers for partition step */ |
||
49 | unsigned size; /* size of the sub-array */ |
||
50 | char *lostk[STKSIZ], *histk[STKSIZ]; |
||
51 | int stkptr; /* stack for saving sub-array to be processed */ |
||
52 | |||
53 | if (num < 2) |
||
54 | return; /* nothing to do */ |
||
55 | |||
56 | stkptr = 0; /* initialize stack */ |
||
57 | |||
58 | lo = (char *)base; |
||
59 | hi = (char *)base + width * (num-1); /* initialize limits */ |
||
60 | |||
61 | /* this entry point is for pseudo-recursion calling: setting |
||
62 | lo and hi and jumping to here is like recursion, but stkptr is |
||
63 | preserved, locals aren't, so we preserve stuff on the stack */ |
||
64 | recurse: |
||
65 | |||
66 | size = (hi - lo) / width + 1; /* number of el's to sort */ |
||
67 | |||
68 | /* below a certain size, it is faster to use a O(n^2) sorting method */ |
||
69 | if (size <= CUTOFF) { |
||
70 | shortsort(lo, hi, width, comp); |
||
71 | } |
||
72 | else { |
||
73 | /* First we pick a partitioning element. The efficiency of the |
||
74 | algorithm demands that we find one that is approximately the median |
||
75 | of the values, but also that we select one fast. We choose the |
||
76 | median of the first, middle, and last elements, to avoid bad |
||
77 | performance in the face of already sorted data, or data that is made |
||
78 | up of multiple sorted runs appended together. Testing shows that a |
||
79 | median-of-three algorithm provides better performance than simply |
||
80 | picking the middle element for the latter case. */ |
||
81 | |||
82 | mid = lo + (size / 2) * width; /* find middle element */ |
||
83 | |||
84 | /* Sort the first, middle, last elements into order */ |
||
85 | if (comp(lo, mid) > 0) { |
||
86 | swap(lo, mid, width); |
||
87 | } |
||
88 | if (comp(lo, hi) > 0) { |
||
89 | swap(lo, hi, width); |
||
90 | } |
||
91 | if (comp(mid, hi) > 0) { |
||
92 | swap(mid, hi, width); |
||
93 | } |
||
94 | |||
95 | /* We now wish to partition the array into three pieces, one consisting |
||
96 | of elements <= partition element, one of elements equal to the |
||
97 | partition element, and one of elements > than it. This is done |
||
98 | below; comments indicate conditions established at every step. */ |
||
99 | |||
100 | loguy = lo; |
||
101 | higuy = hi; |
||
102 | |||
103 | /* Note that higuy decreases and loguy increases on every iteration, |
||
104 | so loop must terminate. */ |
||
105 | for (;;) { |
||
106 | /* lo <= loguy < hi, lo < higuy <= hi, |
||
107 | A[i] <= A[mid] for lo <= i <= loguy, |
||
108 | A[i] > A[mid] for higuy <= i < hi, |
||
109 | A[hi] >= A[mid] */ |
||
110 | |||
111 | /* The doubled loop is to avoid calling comp(mid,mid), since some |
||
112 | existing comparison funcs don't work when passed the same |
||
113 | value for both pointers. */ |
||
114 | |||
115 | if (mid > loguy) { |
||
116 | do { |
||
117 | loguy += width; |
||
118 | } while (loguy < mid && comp(loguy, mid) <= 0); |
||
119 | } |
||
120 | if (mid <= loguy) { |
||
121 | do { |
||
122 | loguy += width; |
||
123 | } while (loguy <= hi && comp(loguy, mid) <= 0); |
||
124 | } |
||
125 | |||
126 | /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy, |
||
127 | either loguy > hi or A[loguy] > A[mid] */ |
||
128 | |||
129 | do { |
||
130 | higuy -= width; |
||
131 | } while (higuy > mid && comp(higuy, mid) > 0); |
||
132 | |||
133 | /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi, |
||
134 | either higuy == lo or A[higuy] <= A[mid] */ |
||
135 | |||
136 | if (higuy < loguy) |
||
137 | break; |
||
138 | |||
139 | /* if loguy > hi or higuy == lo, then we would have exited, so |
||
140 | A[loguy] > A[mid], A[higuy] <= A[mid], |
||
141 | loguy <= hi, higuy > lo */ |
||
142 | |||
143 | swap(loguy, higuy, width); |
||
144 | |||
145 | /* If the partition element was moved, follow it. Only need |
||
146 | to check for mid == higuy, since before the swap, |
||
147 | A[loguy] > A[mid] implies loguy != mid. */ |
||
148 | |||
149 | if (mid == higuy) |
||
150 | mid = loguy; |
||
151 | |||
152 | /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top |
||
153 | of loop is re-established */ |
||
154 | } |
||
155 | |||
156 | /* A[i] <= A[mid] for lo <= i < loguy, |
||
157 | A[i] > A[mid] for higuy < i < hi, |
||
158 | A[hi] >= A[mid] |
||
159 | higuy < loguy |
||
160 | implying: |
||
161 | higuy == loguy-1 |
||
162 | or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */ |
||
163 | |||
164 | /* Find adjacent elements equal to the partition element. The |
||
165 | doubled loop is to avoid calling comp(mid,mid), since some |
||
166 | existing comparison funcs don't work when passed the same value |
||
167 | for both pointers. */ |
||
168 | |||
169 | higuy += width; |
||
170 | if (mid < higuy) { |
||
171 | do { |
||
172 | higuy -= width; |
||
173 | } while (higuy > mid && comp(higuy, mid) == 0); |
||
174 | } |
||
175 | if (mid >= higuy) { |
||
176 | do { |
||
177 | higuy -= width; |
||
178 | } while (higuy > lo && comp(higuy, mid) == 0); |
||
179 | } |
||
180 | |||
181 | /* OK, now we have the following: |
||
182 | higuy < loguy |
||
183 | lo <= higuy <= hi |
||
184 | A[i] <= A[mid] for lo <= i <= higuy |
||
185 | A[i] == A[mid] for higuy < i < loguy |
||
186 | A[i] > A[mid] for loguy <= i < hi |
||
187 | A[hi] >= A[mid] */ |
||
188 | |||
189 | /* We've finished the partition, now we want to sort the subarrays |
||
190 | [lo, higuy] and [loguy, hi]. |
||
191 | We do the smaller one first to minimize stack usage. |
||
192 | We only sort arrays of length 2 or more.*/ |
||
193 | |||
194 | if ( higuy - lo >= hi - loguy ) { |
||
195 | if (lo < higuy) { |
||
196 | lostk[stkptr] = lo; |
||
197 | histk[stkptr] = higuy; |
||
198 | ++stkptr; |
||
199 | } /* save big recursion for later */ |
||
200 | |||
201 | if (loguy < hi) { |
||
202 | lo = loguy; |
||
203 | goto recurse; /* do small recursion */ |
||
204 | } |
||
205 | } |
||
206 | else { |
||
207 | if (loguy < hi) { |
||
208 | lostk[stkptr] = loguy; |
||
209 | histk[stkptr] = hi; |
||
210 | ++stkptr; /* save big recursion for later */ |
||
211 | } |
||
212 | |||
213 | if (lo < higuy) { |
||
214 | hi = higuy; |
||
215 | goto recurse; /* do small recursion */ |
||
216 | } |
||
217 | } |
||
218 | } |
||
219 | |||
220 | /* We have sorted the array, except for any pending sorts on the stack. |
||
221 | Check if there are any, and do them. */ |
||
222 | |||
223 | --stkptr; |
||
224 | if (stkptr >= 0) { |
||
225 | lo = lostk[stkptr]; |
||
226 | hi = histk[stkptr]; |
||
227 | goto recurse; /* pop subarray from stack */ |
||
228 | } |
||
229 | else |
||
230 | return; /* all subarrays done */ |
||
231 | } |
||
232 | |||
233 | |||
234 | /*** |
||
235 | *shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays |
||
236 | *shortsort_s(hi, lo, width, comp, context) - insertion sort for sorting short arrays |
||
237 | * |
||
238 | *Purpose: |
||
239 | * sorts the sub-array of elements between lo and hi (inclusive) |
||
240 | * side effects: sorts in place |
||
241 | * assumes that lo < hi |
||
242 | * |
||
243 | *Entry: |
||
244 | * char *lo = pointer to low element to sort |
||
245 | * char *hi = pointer to high element to sort |
||
246 | * unsigned width = width in bytes of each array element |
||
247 | * int (*comp)() = pointer to function returning analog of strcmp for |
||
248 | * strings, but supplied by user for comparing the array elements. |
||
249 | * it accepts 2 pointers to elements, together with a pointer to a context |
||
250 | * (if present). Returns neg if 1<2, 0 if 1=2, pos if 1>2. |
||
251 | * void *context - pointer to the context in which the function is |
||
252 | * called. This context is passed to the comparison function. |
||
253 | * |
||
254 | *Exit: |
||
255 | * returns void |
||
256 | * |
||
257 | *Exceptions: |
||
258 | * |
||
259 | *******************************************************************************/ |
||
260 | |||
261 | static void shortsort ( |
||
262 | char *lo, |
||
263 | char *hi, |
||
264 | unsigned width, |
||
265 | int (*comp)(const void *, const void *) |
||
266 | ) |
||
267 | { |
||
268 | char *p, *max; |
||
269 | |||
270 | /* Note: in assertions below, i and j are alway inside original bound of |
||
271 | array to sort. */ |
||
272 | |||
273 | while (hi > lo) { |
||
274 | /* A[i] <= A[j] for i <= j, j > hi */ |
||
275 | max = lo; |
||
276 | for (p = lo+width; p <= hi; p += width) { |
||
277 | /* A[i] <= A[max] for lo <= i < p */ |
||
278 | if (comp(p, max) > 0) { |
||
279 | max = p; |
||
280 | } |
||
281 | /* A[i] <= A[max] for lo <= i <= p */ |
||
282 | } |
||
283 | |||
284 | /* A[i] <= A[max] for lo <= i <= hi */ |
||
285 | |||
286 | swap(max, hi, width); |
||
287 | |||
288 | /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */ |
||
289 | |||
290 | hi -= width; |
||
291 | |||
292 | /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */ |
||
293 | } |
||
294 | /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j, |
||
295 | so array is sorted */ |
||
296 | } |
||
297 | |||
298 | /*** |
||
299 | *swap(a, b, width) - swap two elements |
||
300 | * |
||
301 | *Purpose: |
||
302 | * swaps the two array elements of size width |
||
303 | * |
||
304 | *Entry: |
||
305 | * char *a, *b = pointer to two elements to swap |
||
306 | * unsigned width = width in bytes of each array element |
||
307 | * |
||
308 | *Exit: |
||
309 | * returns void |
||
310 | * |
||
311 | *Exceptions: |
||
312 | * |
||
313 | *******************************************************************************/ |
||
314 | |||
315 | static void swap ( |
||
316 | char *a, |
||
317 | char *b, |
||
318 | unsigned width |
||
319 | ) |
||
320 | { |
||
321 | char tmp; |
||
322 | |||
323 | if ( a != b ) |
||
324 | /* Do the swap one character at a time to avoid potential alignment |
||
325 | problems. */ |
||
326 | while ( width-- ) { |
||
327 | tmp = *a; |
||
328 | *a++ = *b; |
||
329 | *b++ = tmp; |
||
330 | } |
||
331 | }>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>>=>=>=>=>=>2,>>>>>>>=>>>=>=>=>=>=>>>>>>>=>=>=>=>=>>=>>>>=>>=>=>=>>=>=>=>=>>>=>=>=>=>=>>>=>=>=>>2,> |