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.3 KiB

  1. using System;
  2. namespace Apewer.Internals
  3. {
  4. // 快速排序。
  5. internal class QuickSorter<T>
  6. {
  7. private const int IntrosortSizeThreshold = 16;
  8. private const int QuickSortDepthThreshold = 32;
  9. private T[] keys;
  10. private T[] items;
  11. private Comparison<T> comparison;
  12. private QuickSorter(T[] keys, T[] items, Comparison<T> comparison)
  13. {
  14. this.keys = keys;
  15. this.items = items;
  16. this.comparison = comparison;
  17. }
  18. private void SwapIfGreaterWithItems(int a, int b)
  19. {
  20. if (a != b && comparison(keys[a], keys[b]) > 0)
  21. {
  22. T temp1 = keys[a];
  23. keys[a] = keys[b];
  24. keys[b] = temp1;
  25. if (items != null)
  26. {
  27. T temp2 = items[a];
  28. items[a] = items[b];
  29. items[b] = temp2;
  30. }
  31. }
  32. }
  33. private void Swap(int i, int j)
  34. {
  35. T temp1 = keys[i];
  36. keys[i] = keys[j];
  37. keys[j] = temp1;
  38. if (items != null)
  39. {
  40. T temp2 = items[i];
  41. items[i] = items[j];
  42. items[j] = temp2;
  43. }
  44. }
  45. private void Sort(int left, int length)
  46. {
  47. // if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) IntrospectiveSort(left, length);
  48. DepthLimitedQuickSort(left, length + left - 1, 32);
  49. }
  50. private void DepthLimitedQuickSort(int left, int right, int depthLimit)
  51. {
  52. do
  53. {
  54. if (depthLimit == 0)
  55. {
  56. Heapsort(left, right);
  57. break;
  58. }
  59. int i = left;
  60. int num = right;
  61. int median = GetMedian(i, num);
  62. SwapIfGreaterWithItems(i, median);
  63. SwapIfGreaterWithItems(i, num);
  64. SwapIfGreaterWithItems(median, num);
  65. T temp1 = keys[median];
  66. do
  67. {
  68. for (; comparison(keys[i], temp1) < 0; i++)
  69. {
  70. }
  71. while (comparison(temp1, keys[num]) < 0)
  72. {
  73. num--;
  74. }
  75. if (i > num)
  76. {
  77. break;
  78. }
  79. if (i < num)
  80. {
  81. T temp2 = keys[i];
  82. keys[i] = keys[num];
  83. keys[num] = temp2;
  84. if (items != null)
  85. {
  86. T temp3 = items[i];
  87. items[i] = items[num];
  88. items[num] = temp3;
  89. }
  90. }
  91. i++;
  92. num--;
  93. }
  94. while (i <= num);
  95. depthLimit--;
  96. if (num - left <= right - i)
  97. {
  98. if (left < num)
  99. {
  100. DepthLimitedQuickSort(left, num, depthLimit);
  101. }
  102. left = i;
  103. }
  104. else
  105. {
  106. if (i < right)
  107. {
  108. DepthLimitedQuickSort(i, right, depthLimit);
  109. }
  110. right = num;
  111. }
  112. }
  113. while (left < right);
  114. }
  115. private void IntrospectiveSort(int left, int length)
  116. {
  117. if (length >= 2)
  118. {
  119. IntroSort(left, length + left - 1, 2 * FloorLog2(keys.Length));
  120. }
  121. }
  122. private void IntroSort(int lo, int hi, int depthLimit)
  123. {
  124. while (hi > lo)
  125. {
  126. int num = hi - lo + 1;
  127. if (num <= 16)
  128. {
  129. switch (num)
  130. {
  131. case 1:
  132. break;
  133. case 2:
  134. SwapIfGreaterWithItems(lo, hi);
  135. break;
  136. case 3:
  137. SwapIfGreaterWithItems(lo, hi - 1);
  138. SwapIfGreaterWithItems(lo, hi);
  139. SwapIfGreaterWithItems(hi - 1, hi);
  140. break;
  141. default:
  142. InsertionSort(lo, hi);
  143. break;
  144. }
  145. break;
  146. }
  147. if (depthLimit == 0)
  148. {
  149. Heapsort(lo, hi);
  150. break;
  151. }
  152. depthLimit--;
  153. int num2 = PickPivotAndPartition(lo, hi);
  154. IntroSort(num2 + 1, hi, depthLimit);
  155. hi = num2 - 1;
  156. }
  157. }
  158. private int PickPivotAndPartition(int lo, int hi)
  159. {
  160. int num1 = lo + (hi - lo) / 2;
  161. SwapIfGreaterWithItems(lo, num1);
  162. SwapIfGreaterWithItems(lo, hi);
  163. SwapIfGreaterWithItems(num1, hi);
  164. T temp = keys[num1];
  165. Swap(num1, hi - 1);
  166. int num2 = lo;
  167. int num3 = hi - 1;
  168. while (num2 < num3)
  169. {
  170. while (comparison(keys[++num2], temp) < 0)
  171. {
  172. }
  173. while (comparison(temp, keys[--num3]) < 0)
  174. {
  175. }
  176. if (num2 >= num3)
  177. {
  178. break;
  179. }
  180. Swap(num2, num3);
  181. }
  182. Swap(num2, hi - 1);
  183. return num2;
  184. }
  185. private void Heapsort(int lo, int hi)
  186. {
  187. int num = hi - lo + 1;
  188. for (int num2 = num / 2; num2 >= 1; num2--)
  189. {
  190. DownHeap(num2, num, lo);
  191. }
  192. for (int num3 = num; num3 > 1; num3--)
  193. {
  194. Swap(lo, lo + num3 - 1);
  195. DownHeap(1, num3 - 1, lo);
  196. }
  197. }
  198. private void DownHeap(int i, int n, int lo)
  199. {
  200. T temp1 = keys[lo + i - 1];
  201. T temp2 = (items != null) ? items[lo + i - 1] : default;
  202. while (i <= n / 2)
  203. {
  204. int num = 2 * i;
  205. if (num < n && comparison(keys[lo + num - 1], keys[lo + num]) < 0)
  206. {
  207. num++;
  208. }
  209. if (comparison(temp1, keys[lo + num - 1]) >= 0)
  210. {
  211. break;
  212. }
  213. keys[lo + i - 1] = keys[lo + num - 1];
  214. if (items != null)
  215. {
  216. items[lo + i - 1] = items[lo + num - 1];
  217. }
  218. i = num;
  219. }
  220. keys[lo + i - 1] = temp1;
  221. if (items != null)
  222. {
  223. items[lo + i - 1] = temp2;
  224. }
  225. }
  226. private void InsertionSort(int lo, int hi)
  227. {
  228. for (int i = lo; i < hi; i++)
  229. {
  230. int num = i;
  231. T temp1 = keys[i + 1];
  232. T temp2 = (items != default) ? items[i + 1] : default;
  233. while (num >= lo && comparison(temp1, keys[num]) < 0)
  234. {
  235. keys[num + 1] = keys[num];
  236. if (items != null)
  237. {
  238. items[num + 1] = items[num];
  239. }
  240. num--;
  241. }
  242. keys[num + 1] = temp1;
  243. if (items != null)
  244. {
  245. items[num + 1] = temp2;
  246. }
  247. }
  248. }
  249. private static int FloorLog2(int n)
  250. {
  251. int num = 0;
  252. while (n >= 1)
  253. {
  254. num++;
  255. n /= 2;
  256. }
  257. return num;
  258. }
  259. private static int GetMedian(int low, int hi)
  260. {
  261. return low + (hi - low >> 1);
  262. }
  263. public static void Sort(T[] array, Comparison<T> comparison)
  264. {
  265. var instance = new QuickSorter<T>(array, null, comparison);
  266. instance.Sort(0, array.Length);
  267. }
  268. }
  269. }