OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * |
| 4 * Copyright (C) 2003, International Business Machines |
| 5 * Corporation and others. All Rights Reserved. |
| 6 * |
| 7 ******************************************************************************* |
| 8 * file name: uarrsort.c |
| 9 * encoding: US-ASCII |
| 10 * tab size: 8 (not used) |
| 11 * indentation:4 |
| 12 * |
| 13 * created on: 2003aug04 |
| 14 * created by: Markus W. Scherer |
| 15 * |
| 16 * Internal function for sorting arrays. |
| 17 */ |
| 18 |
| 19 #include "unicode/utypes.h" |
| 20 #include "cmemory.h" |
| 21 #include "uarrsort.h" |
| 22 |
| 23 enum { |
| 24 MIN_QSORT=9, /* from Knuth */ |
| 25 STACK_ITEM_SIZE=200 |
| 26 }; |
| 27 |
| 28 /* UComparator convenience implementations ---------------------------------- */ |
| 29 |
| 30 U_CAPI int32_t U_EXPORT2 |
| 31 uprv_uint16Comparator(const void *context, const void *left, const void *right)
{ |
| 32 return (int32_t)*(const uint16_t *)left - (int32_t)*(const uint16_t *)right; |
| 33 } |
| 34 |
| 35 U_CAPI int32_t U_EXPORT2 |
| 36 uprv_int32Comparator(const void *context, const void *left, const void *right) { |
| 37 return *(const int32_t *)left - *(const int32_t *)right; |
| 38 } |
| 39 |
| 40 U_CAPI int32_t U_EXPORT2 |
| 41 uprv_uint32Comparator(const void *context, const void *left, const void *right)
{ |
| 42 uint32_t l=*(const uint32_t *)left, r=*(const uint32_t *)right; |
| 43 |
| 44 /* compare directly because (l-r) would overflow the int32_t result */ |
| 45 if(l<r) { |
| 46 return -1; |
| 47 } else if(l==r) { |
| 48 return 0; |
| 49 } else /* l>r */ { |
| 50 return 1; |
| 51 } |
| 52 } |
| 53 |
| 54 /* Straight insertion sort from Knuth vol. III, pg. 81 ---------------------- */ |
| 55 |
| 56 static void |
| 57 doInsertionSort(char *array, int32_t start, int32_t limit, int32_t itemSize, |
| 58 UComparator *cmp, const void *context, void *pv) { |
| 59 int32_t i, j; |
| 60 |
| 61 for(j=start+1; j<limit; ++j) { |
| 62 /* v=array[j] */ |
| 63 uprv_memcpy(pv, array+j*itemSize, itemSize); |
| 64 |
| 65 for(i=j; i>start; --i) { |
| 66 if(/* v>=array[i-1] */ cmp(context, pv, array+(i-1)*itemSize)>=0) { |
| 67 break; |
| 68 } |
| 69 |
| 70 /* array[i]=array[i-1]; */ |
| 71 uprv_memcpy(array+i*itemSize, array+(i-1)*itemSize, itemSize); |
| 72 } |
| 73 |
| 74 if(i!=j) { |
| 75 /* array[i]=v; */ |
| 76 uprv_memcpy(array+i*itemSize, pv, itemSize); |
| 77 } |
| 78 } |
| 79 } |
| 80 |
| 81 static void |
| 82 insertionSort(char *array, int32_t length, int32_t itemSize, |
| 83 UComparator *cmp, const void *context, UErrorCode *pErrorCode) { |
| 84 UAlignedMemory v[STACK_ITEM_SIZE/sizeof(UAlignedMemory)+1]; |
| 85 void *pv; |
| 86 |
| 87 /* allocate an intermediate item variable (v) */ |
| 88 if(itemSize<=STACK_ITEM_SIZE) { |
| 89 pv=v; |
| 90 } else { |
| 91 pv=uprv_malloc(itemSize); |
| 92 if(pv==NULL) { |
| 93 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; |
| 94 return; |
| 95 } |
| 96 } |
| 97 |
| 98 doInsertionSort(array, 0, length, itemSize, cmp, context, pv); |
| 99 |
| 100 if(pv!=v) { |
| 101 uprv_free(pv); |
| 102 } |
| 103 } |
| 104 |
| 105 /* QuickSort ---------------------------------------------------------------- */ |
| 106 |
| 107 /* |
| 108 * This implementation is semi-recursive: |
| 109 * It recurses for the smaller sub-array to shorten the recursion depth, |
| 110 * and loops for the larger sub-array. |
| 111 * |
| 112 * Loosely after QuickSort algorithms in |
| 113 * Niklaus Wirth |
| 114 * Algorithmen und Datenstrukturen mit Modula-2 |
| 115 * B.G. Teubner Stuttgart |
| 116 * 4. Auflage 1986 |
| 117 * ISBN 3-519-02260-5 |
| 118 */ |
| 119 static void |
| 120 subQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize, |
| 121 UComparator *cmp, const void *context, |
| 122 void *px, void *pw) { |
| 123 int32_t left, right; |
| 124 |
| 125 /* start and left are inclusive, limit and right are exclusive */ |
| 126 do { |
| 127 if((start+MIN_QSORT)>=limit) { |
| 128 doInsertionSort(array, start, limit, itemSize, cmp, context, px); |
| 129 break; |
| 130 } |
| 131 |
| 132 left=start; |
| 133 right=limit; |
| 134 |
| 135 /* x=array[middle] */ |
| 136 uprv_memcpy(px, array+((start+limit)/2)*itemSize, itemSize); |
| 137 |
| 138 do { |
| 139 while(/* array[left]<x */ |
| 140 cmp(context, array+left*itemSize, px)<0 |
| 141 ) { |
| 142 ++left; |
| 143 } |
| 144 while(/* x<array[right-1] */ |
| 145 cmp(context, px, array+(right-1)*itemSize)<0 |
| 146 ) { |
| 147 --right; |
| 148 } |
| 149 |
| 150 /* swap array[left] and array[right-1] via w; ++left; --right */ |
| 151 if(left<right) { |
| 152 --right; |
| 153 |
| 154 if(left<right) { |
| 155 uprv_memcpy(pw, array+left*itemSize, itemSize); |
| 156 uprv_memcpy(array+left*itemSize, array+right*itemSize, itemS
ize); |
| 157 uprv_memcpy(array+right*itemSize, pw, itemSize); |
| 158 } |
| 159 |
| 160 ++left; |
| 161 } |
| 162 } while(left<right); |
| 163 |
| 164 /* sort sub-arrays */ |
| 165 if((right-start)<(limit-left)) { |
| 166 /* sort [start..right[ */ |
| 167 if(start<(right-1)) { |
| 168 subQuickSort(array, start, right, itemSize, cmp, context, px, pw
); |
| 169 } |
| 170 |
| 171 /* sort [left..limit[ */ |
| 172 start=left; |
| 173 } else { |
| 174 /* sort [left..limit[ */ |
| 175 if(left<(limit-1)) { |
| 176 subQuickSort(array, left, limit, itemSize, cmp, context, px, pw)
; |
| 177 } |
| 178 |
| 179 /* sort [start..right[ */ |
| 180 limit=right; |
| 181 } |
| 182 } while(start<(limit-1)); |
| 183 } |
| 184 |
| 185 static void |
| 186 quickSort(char *array, int32_t length, int32_t itemSize, |
| 187 UComparator *cmp, const void *context, UErrorCode *pErrorCode) { |
| 188 UAlignedMemory xw[(2*STACK_ITEM_SIZE)/sizeof(UAlignedMemory)+1]; |
| 189 void *p; |
| 190 |
| 191 /* allocate two intermediate item variables (x and w) */ |
| 192 if(itemSize<=STACK_ITEM_SIZE) { |
| 193 p=xw; |
| 194 } else { |
| 195 p=uprv_malloc(2*itemSize); |
| 196 if(p==NULL) { |
| 197 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; |
| 198 return; |
| 199 } |
| 200 } |
| 201 |
| 202 subQuickSort(array, 0, length, itemSize, |
| 203 cmp, context, p, (char *)p+itemSize); |
| 204 |
| 205 if(p!=xw) { |
| 206 uprv_free(p); |
| 207 } |
| 208 } |
| 209 |
| 210 /* uprv_sortArray() API ----------------------------------------------------- */ |
| 211 |
| 212 /* |
| 213 * Check arguments, select an appropriate implementation, |
| 214 * cast the array to char * so that array+i*itemSize works. |
| 215 */ |
| 216 U_CAPI void U_EXPORT2 |
| 217 uprv_sortArray(void *array, int32_t length, int32_t itemSize, |
| 218 UComparator *cmp, const void *context, |
| 219 UBool sortStable, UErrorCode *pErrorCode) { |
| 220 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
| 221 return; |
| 222 } |
| 223 if((length>0 && array==NULL) || length<0 || itemSize<=0 || cmp==NULL) { |
| 224 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
| 225 return; |
| 226 } |
| 227 |
| 228 if(length<=1) { |
| 229 return; |
| 230 } else if(length<MIN_QSORT || sortStable) { |
| 231 insertionSort((char *)array, length, itemSize, cmp, context, pErrorCode)
; |
| 232 /* could add heapSort or similar for stable sorting of longer arrays */ |
| 233 } else { |
| 234 quickSort((char *)array, length, itemSize, cmp, context, pErrorCode); |
| 235 } |
| 236 } |
OLD | NEW |