Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. sort.c
  5. Abstract:
  6. This module contains routines used for efficiently sorting information.
  7. Author:
  8. Abolade Gbadegesin (aboladeg) 18-Feb-1998
  9. Based on version written for user-mode RAS user-interface.
  10. (net\routing\ras\ui\common\nouiutil\noui.c).
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. NTSTATUS
  16. ShellSort(
  17. VOID* pItemTable,
  18. ULONG dwItemSize,
  19. ULONG dwItemCount,
  20. PCOMPARE_CALLBACK CompareCallback,
  21. VOID* pDestinationTable OPTIONAL
  22. )
  23. /* Sort an array of items in-place using shell-sort.
  24. ** This function calls ShellSortIndirect to sort a table of pointers
  25. ** to table items. We then move the items into place by copying.
  26. ** This algorithm allows us to guarantee that the number
  27. ** of copies necessary in the worst case is N + 1.
  28. **
  29. ** Note that if the caller merely needs to know the sorted order
  30. ** of the array, ShellSortIndirect should be called since that function
  31. ** avoids moving items altogether, and instead fills an array with pointers
  32. ** to the array items in the correct order. The array items can then
  33. ** be accessed through the array of pointers.
  34. */
  35. {
  36. VOID** ppItemTable;
  37. LONG N;
  38. LONG i;
  39. UCHAR *a, **p, *t = NULL;
  40. if (!dwItemCount) { return STATUS_SUCCESS; }
  41. /* allocate space for the table of pointers.
  42. */
  43. ppItemTable =
  44. ExAllocatePoolWithTag(
  45. NonPagedPool,
  46. dwItemCount * sizeof(VOID*),
  47. NAT_TAG_SORT
  48. );
  49. if (!ppItemTable) { return STATUS_NO_MEMORY; }
  50. /* call ShellSortIndirect to fill our table of pointers
  51. ** with the sorted positions for each table element.
  52. */
  53. ShellSortIndirect(
  54. pItemTable, ppItemTable, dwItemSize, dwItemCount, CompareCallback );
  55. /* now that we know the sort order, move each table item into place.
  56. ** This is easy if we are sorting to a different array.
  57. */
  58. if (pDestinationTable) {
  59. for (i = 0; i < (LONG)dwItemCount; i++)
  60. {
  61. RtlCopyMemory(
  62. (PUCHAR)pDestinationTable + i * dwItemSize,
  63. ppItemTable[i],
  64. dwItemSize
  65. );
  66. }
  67. ExFreePool(ppItemTable);
  68. return STATUS_SUCCESS;
  69. }
  70. /* We are sorting in-place, which is a little more involved.
  71. ** This involves going through the table of pointers making sure
  72. ** that the item which should be in 'i' is in fact in 'i', moving
  73. ** things around if necessary to achieve this condition.
  74. */
  75. a = (UCHAR*)pItemTable;
  76. p = (UCHAR**)ppItemTable;
  77. N = (LONG)dwItemCount;
  78. for (i = 0; i < N; i++)
  79. {
  80. LONG j, k;
  81. UCHAR* ai = (a + i * dwItemSize), *ak, *aj;
  82. /* see if item 'i' is not in-place
  83. */
  84. if (p[i] != ai)
  85. {
  86. /* item 'i' isn't in-place, so we'll have to move it.
  87. ** if we've delayed allocating a temporary buffer so far,
  88. ** we'll need one now.
  89. */
  90. if (!t) {
  91. t =
  92. ExAllocatePoolWithTag(
  93. NonPagedPool,
  94. dwItemSize,
  95. NAT_TAG_SORT
  96. );
  97. if (!t) {
  98. ExFreePool(ppItemTable);
  99. return STATUS_NO_MEMORY;
  100. }
  101. }
  102. /* save a copy of the item to be overwritten
  103. */
  104. RtlCopyMemory(t, ai, dwItemSize);
  105. k = i;
  106. ak = ai;
  107. /* Now move whatever item is occupying the space where it should be.
  108. ** This may involve moving the item occupying the space where
  109. ** it should be, etc.
  110. */
  111. do
  112. {
  113. /* copy the item which should be in position 'j'
  114. ** over the item which is currently in position 'j'.
  115. */
  116. j = k;
  117. aj = ak;
  118. RtlCopyMemory(aj, p[j], dwItemSize);
  119. /* set 'k' to the position from which we copied
  120. ** into position 'j'; this is where we will copy
  121. ** the next out-of-place item in the array.
  122. */
  123. ak = p[j];
  124. k = (ULONG)(ak - a) / dwItemSize;
  125. /* keep the array of position pointers up-to-date;
  126. ** the contents of 'aj' are now in their sorted position.
  127. */
  128. p[j] = aj;
  129. } while (ak != ai);
  130. /* now write the item which we first overwrote.
  131. */
  132. RtlCopyMemory(aj, t, dwItemSize);
  133. }
  134. }
  135. if (t) { ExFreePool(t); }
  136. ExFreePool(ppItemTable);
  137. return STATUS_SUCCESS;
  138. }
  139. VOID
  140. ShellSortIndirect(
  141. VOID* pItemTable,
  142. VOID** ppItemTable,
  143. ULONG dwItemSize,
  144. ULONG dwItemCount,
  145. PCOMPARE_CALLBACK CompareCallback
  146. )
  147. /* Sorts an array of items indirectly using shell-sort.
  148. ** 'pItemTable' points to the table of items, 'dwItemCount' is the number
  149. ** of items in the table, and 'CompareCallback' is a function called
  150. ** to compare items.
  151. **
  152. ** Rather than sort the items by moving them around,
  153. ** we sort them by initializing the table of pointers 'ppItemTable'
  154. ** with pointers such that 'ppItemTable[i]' contains a pointer
  155. ** into 'pItemTable' for the item which would be in position 'i'
  156. ** if 'pItemTable' were sorted.
  157. **
  158. ** For instance, given an array pItemTable of 5 strings as follows
  159. **
  160. ** pItemTable[0]: "xyz"
  161. ** pItemTable[1]: "abc"
  162. ** pItemTable[2]: "mno"
  163. ** pItemTable[3]: "qrs"
  164. ** pItemTable[4]: "def"
  165. **
  166. ** on output ppItemTable contains the following pointers
  167. **
  168. ** ppItemTable[0]: &pItemTable[1] ("abc")
  169. ** ppItemTable[1]: &pItemTable[4] ("def")
  170. ** ppItemTable[2]: &pItemTable[2] ("mno")
  171. ** ppItemTable[3]: &pItemTable[3] ("qrs")
  172. ** ppItemTable[4]: &pItemTable[0] ("xyz")
  173. **
  174. ** and the contents of pItemTable are untouched.
  175. ** And the caller can print out the array in sorted order using
  176. ** for (i = 0; i < 4; i++) {
  177. ** printf("%s\n", (char *)*ppItemTable[i]);
  178. ** }
  179. */
  180. {
  181. /* The following algorithm is derived from Sedgewick's Shellsort,
  182. ** as given in "Algorithms in C++".
  183. **
  184. ** The Shellsort algorithm sorts the table by viewing it as
  185. ** a number of interleaved arrays, each of whose elements are 'h'
  186. ** spaces apart for some 'h'. Each array is sorted separately,
  187. ** starting with the array whose elements are farthest apart and
  188. ** ending with the array whose elements are closest together.
  189. ** Since the 'last' such array always has elements next to each other,
  190. ** this degenerates to Insertion sort, but by the time we get down
  191. ** to the 'last' array, the table is pretty much sorted.
  192. **
  193. ** The sequence of values chosen below for 'h' is 1, 4, 13, 40, 121, ...
  194. ** and the worst-case running time for the sequence is N^(3/2), where
  195. ** the running time is measured in number of comparisons.
  196. */
  197. ULONG dwErr;
  198. LONG i, j, h, N;
  199. UCHAR* a, *v, **p;
  200. a = (UCHAR*)pItemTable;
  201. p = (UCHAR**)ppItemTable;
  202. N = (LONG)dwItemCount;
  203. /* Initialize the table of position pointers.
  204. */
  205. for (i = 0; i < N; i++) { p[i] = (a + i * dwItemSize); }
  206. /* Move 'h' to the largest increment in our series
  207. */
  208. for (h = 1; h < N/9; h = 3 * h + 1) { }
  209. /* For each increment in our series, sort the 'array' for that increment
  210. */
  211. for ( ; h > 0; h /= 3)
  212. {
  213. /* For each element in the 'array', get the pointer to its
  214. ** sorted position.
  215. */
  216. for (i = h; i < N; i++)
  217. {
  218. /* save the pointer to be inserted
  219. */
  220. v = p[i]; j = i;
  221. /* Move all the larger elements to the right
  222. */
  223. while (j >= h && CompareCallback(p[j - h], v) > 0)
  224. {
  225. p[j] = p[j - h]; j -= h;
  226. }
  227. /* put the saved pointer in the position where we stopped.
  228. */
  229. p[j] = v;
  230. }
  231. }
  232. }