qsort.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. qsort.c
  9. Abstract:
  10. This module implements the QuickSort standard C library function.
  11. Author:
  12. Evan Green 26-Jun-2013
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "libcp.h"
  20. #include <assert.h>
  21. #include <stdlib.h>
  22. //
  23. // --------------------------------------------------------------------- Macros
  24. //
  25. //
  26. // This macro is a helper to the quicksort swap macro. It gets a pointer to a
  27. // void pointer at the given index.
  28. //
  29. #define QUICKSORT_ELEMENT(_Base, _ElementSize, _Index) \
  30. (*((void **)((_Base) + ((_ElementSize) * (_Index)))))
  31. //
  32. // This macro either performs an exchange directly for pointer sized elements,
  33. // or calls the bytewise swap function to exchange byte for byte. It assumes
  34. // the presence of a void pointer local called SwapPointer.
  35. //
  36. #define QUICKSORT_SWAP(_Base, _ElementSize, _FirstIndex, _SecondIndex) \
  37. { \
  38. if ((_ElementSize) == sizeof(void *)) { \
  39. SwapPointer = QUICKSORT_ELEMENT(_Base, _ElementSize, _FirstIndex); \
  40. QUICKSORT_ELEMENT(_Base, _ElementSize, _FirstIndex) = \
  41. QUICKSORT_ELEMENT(_Base, _ElementSize, _SecondIndex); \
  42. \
  43. QUICKSORT_ELEMENT(_Base, _ElementSize, _SecondIndex) = \
  44. SwapPointer; \
  45. } else { \
  46. ClpQuickSortSwap((_Base), \
  47. (_ElementSize), \
  48. (_FirstIndex), \
  49. (_SecondIndex)); \
  50. } \
  51. }
  52. //
  53. // ---------------------------------------------------------------- Definitions
  54. //
  55. //
  56. // ------------------------------------------------------ Data Type Definitions
  57. //
  58. //
  59. // ----------------------------------------------- Internal Function Prototypes
  60. //
  61. VOID
  62. ClpQuickSort (
  63. void *ArrayBase,
  64. size_t ElementSize,
  65. ssize_t StartIndex,
  66. ssize_t EndIndex,
  67. int (*CompareFunction)(const void *, const void *)
  68. );
  69. VOID
  70. ClpQuickSortSwap (
  71. void *ArrayBase,
  72. size_t ElementSize,
  73. ssize_t FirstIndex,
  74. ssize_t SecondIndex
  75. );
  76. //
  77. // -------------------------------------------------------------------- Globals
  78. //
  79. //
  80. // ------------------------------------------------------------------ Functions
  81. //
  82. LIBC_API
  83. void
  84. qsort (
  85. void *ArrayBase,
  86. size_t ElementCount,
  87. size_t ElementSize,
  88. int (*CompareFunction)(const void *, const void *)
  89. )
  90. /*++
  91. Routine Description:
  92. This routine sorts an array of items in place using the QuickSort algorithm.
  93. Arguments:
  94. ArrayBase - Supplies a pointer to the array of items that will get pushed
  95. around.
  96. ElementCount - Supplies the number of elements in the array.
  97. ElementSize - Supplies the size of one of the elements.
  98. CompareFunction - Supplies a pointer to a function that will be used to
  99. compare elements. The function takes in two pointers that will point
  100. within the array. It returns less than zero if the first element is
  101. less than the second, zero if the first element is equal to the second,
  102. and greater than zero if the first element is greater than the second.
  103. The routine must not modify the array itself or inconsistently
  104. report comparisons, otherwise the sorting will not come out correctly.
  105. Return Value:
  106. None.
  107. --*/
  108. {
  109. assert(ElementCount < (((size_t)-1) >> 1));
  110. assert(ElementSize < (((size_t)-1) >> 1));
  111. if (ElementCount > 1) {
  112. ClpQuickSort(ArrayBase,
  113. ElementSize,
  114. 0,
  115. ElementCount - 1,
  116. CompareFunction);
  117. }
  118. return;
  119. }
  120. //
  121. // --------------------------------------------------------- Internal Functions
  122. //
  123. VOID
  124. ClpQuickSort (
  125. void *ArrayBase,
  126. size_t ElementSize,
  127. ssize_t StartIndex,
  128. ssize_t EndIndex,
  129. int (*CompareFunction)(const void *, const void *)
  130. )
  131. /*++
  132. Routine Description:
  133. This routine sorts an array of items in place using the QuickSort algorithm.
  134. Arguments:
  135. ArrayBase - Supplies a pointer to the array of items that will get pushed
  136. around.
  137. ElementSize - Supplies the size of one of the elements.
  138. StartIndex - Supplies the starting index of the array to sort, inclusive.
  139. EndIndex - Supplies the ending index of the array to sort, inclusive.
  140. CompareFunction - Supplies a pointer to a function that will be used to
  141. compare elements. The function takes in two pointers that will point
  142. within the array. It returns less than zero if the first element is
  143. less than the second, zero if the first element is equal to the second,
  144. and greater than zero if the first element is greater than the second.
  145. The routine must not modify the array itself or inconsistently
  146. report comparisons, otherwise the sorting will not come out correctly.
  147. Return Value:
  148. None.
  149. --*/
  150. {
  151. int CompareResult;
  152. ssize_t EqualIndex;
  153. ssize_t LargerIndex;
  154. ssize_t LargestIndex;
  155. void *LastElement;
  156. ssize_t SmallerIndex;
  157. ssize_t SmallestIndex;
  158. void *SwapPointer;
  159. if (EndIndex <= StartIndex) {
  160. return;
  161. }
  162. LastElement = ArrayBase + (EndIndex * ElementSize);
  163. SmallerIndex = StartIndex - 1;
  164. SmallestIndex = StartIndex - 1;
  165. LargerIndex = EndIndex;
  166. LargestIndex = EndIndex;
  167. //
  168. // Loop swapping elements that are on the wrong side of the pivot (which is
  169. // selected to be the last element). The loop stops when the indices cross.
  170. //
  171. while (TRUE) {
  172. //
  173. // Scan along as long as the current value is less than the last value.
  174. //
  175. while (TRUE) {
  176. SmallerIndex += 1;
  177. if (SmallerIndex == EndIndex) {
  178. break;
  179. }
  180. CompareResult =
  181. CompareFunction(ArrayBase + (SmallerIndex * ElementSize),
  182. LastElement);
  183. if (CompareResult >= 0) {
  184. break;
  185. }
  186. }
  187. //
  188. // Scan down as long as the current value is greater than the last
  189. // value.
  190. //
  191. while (TRUE) {
  192. LargerIndex -= 1;
  193. CompareResult =
  194. CompareFunction(LastElement,
  195. ArrayBase + (LargerIndex * ElementSize));
  196. if (CompareResult >= 0) {
  197. break;
  198. }
  199. if (LargerIndex == StartIndex) {
  200. break;
  201. }
  202. }
  203. //
  204. // Stop if the paths crossed, as that means everything's on the correct
  205. // side of the pivot if the pivot were here.
  206. //
  207. if (SmallerIndex >= LargerIndex) {
  208. break;
  209. }
  210. //
  211. // Exchange the two, as they're both on the wrong side of the pivot.
  212. //
  213. if (SmallerIndex != LargerIndex) {
  214. QUICKSORT_SWAP(ArrayBase, ElementSize, SmallerIndex, LargerIndex);
  215. }
  216. //
  217. // Move keys equal to the partitioning element over to the ends of the
  218. // arrays. This is the beginning of what's called Bentley-McIlroy 3-way
  219. // partitioning, and it helps to handle an array with lots of
  220. // elements equal to the pivot. So the array is going to look like this:
  221. // | equal | less | xxx (unsorted) | greater | equal |
  222. // At the end, swap the equals to the center so that it looks like:
  223. // | less | equal | greater |
  224. // This has the benefit that it always uses N - 1 three way compares,
  225. // there's no extra overhead if there are no equal keys, and only one
  226. // extra exchange per equal key.
  227. //
  228. CompareResult =
  229. CompareFunction(ArrayBase + (SmallerIndex * ElementSize),
  230. LastElement);
  231. if (CompareResult == 0) {
  232. SmallestIndex += 1;
  233. QUICKSORT_SWAP(ArrayBase, ElementSize, SmallestIndex, SmallerIndex);
  234. }
  235. CompareResult =
  236. CompareFunction(LastElement,
  237. ArrayBase + (LargerIndex * ElementSize));
  238. if (CompareResult == 0) {
  239. LargestIndex -= 1;
  240. QUICKSORT_SWAP(ArrayBase, ElementSize, LargerIndex, LargestIndex);
  241. }
  242. }
  243. //
  244. // Put the pivot into place.
  245. //
  246. QUICKSORT_SWAP(ArrayBase, ElementSize, SmallerIndex, EndIndex);
  247. //
  248. // Move lower equal elements back up to the middle, and remove them from
  249. // the partition of things that need to be resorted.
  250. //
  251. LargerIndex = SmallerIndex + 1;
  252. SmallerIndex -= 1;
  253. for (EqualIndex = StartIndex; EqualIndex < SmallestIndex; EqualIndex += 1) {
  254. QUICKSORT_SWAP(ArrayBase,
  255. ElementSize,
  256. EqualIndex,
  257. SmallerIndex);
  258. SmallerIndex -= 1;
  259. }
  260. //
  261. // Move upper equal elements back down to the middle, and remove them from
  262. // the partition of things that need to be resorted.
  263. //
  264. for (EqualIndex = EndIndex - 1;
  265. EqualIndex > LargestIndex;
  266. EqualIndex -= 1) {
  267. QUICKSORT_SWAP(ArrayBase,
  268. ElementSize,
  269. LargerIndex,
  270. EqualIndex);
  271. LargerIndex += 1;
  272. }
  273. //
  274. // Sort the bottom half and then the top half.
  275. //
  276. if (SmallerIndex > StartIndex) {
  277. ClpQuickSort(ArrayBase,
  278. ElementSize,
  279. StartIndex,
  280. SmallerIndex,
  281. CompareFunction);
  282. }
  283. if (EndIndex > LargerIndex) {
  284. ClpQuickSort(ArrayBase,
  285. ElementSize,
  286. LargerIndex,
  287. EndIndex,
  288. CompareFunction);
  289. }
  290. return;
  291. }
  292. VOID
  293. ClpQuickSortSwap (
  294. void *ArrayBase,
  295. size_t ElementSize,
  296. ssize_t FirstIndex,
  297. ssize_t SecondIndex
  298. )
  299. /*++
  300. Routine Description:
  301. This routine swaps two elements in the given array.
  302. Arguments:
  303. ArrayBase - Supplies a pointer to the array of items that will get pushed
  304. around.
  305. ElementSize - Supplies the size of one of the elements.
  306. FirstIndex - Supplies the first index of the indices to exchange.
  307. SecondIndex - Supplies the second index of the indices to exchange.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. ssize_t ByteIndex;
  313. unsigned char *FirstElement;
  314. unsigned char *SecondElement;
  315. unsigned char Swap;
  316. FirstElement = (unsigned char *)ArrayBase + (ElementSize * FirstIndex);
  317. SecondElement = (unsigned char *)ArrayBase + (ElementSize * SecondIndex);
  318. for (ByteIndex = 0; ByteIndex < ElementSize; ByteIndex += 1) {
  319. Swap = FirstElement[ByteIndex];
  320. FirstElement[ByteIndex] = SecondElement[ByteIndex];
  321. SecondElement[ByteIndex] = Swap;
  322. }
  323. return;
  324. }