int[]排序

  • 长度大于QUICKSORT_THRESHOLD(286)时,调用sort方法
    • 长度大于INSERTION_SORT_THRESHOLD时,采用快排
      • 优化:对Pivot的选取。通过位运算,获取长度1/7近似值。以长度中点、中点左右1/7、2/7共5个值作为Pivot
    • 小于的,使用插入排序
  • 否则,判断是否高度结构化(即,是否已经接近排序完成
    • 定义一个常量MAX_RUN_COUNT = 67;
    • 定义一个计数器int count = 0; 定义一个数组int[] run 使之长度为MAX_RUN_COUNT + 1;
    • 令run[0] = left, 然后从传入数组的最左侧left开始遍历,
      • 若数组的前n个元素均为升序/降序排列, 而第n + 1个元素的升/降序发生了改变, 则++count,并将第n个元素的索引存入run[conut]
      • 若数组中连续相等的元素长度超过MAX_RUN_LENGTH(33),就调用快排
      • 在遍历过程中,将降序的序列进行翻转变为升序
    • 如果conut<MAX_RUN_COUNT,即升序降序改变次数小于67次,就认为是高度结构化的
  • 高度结构化的,如果还未排好序,使用归并排序
  • 未高度结构化的,使用快排

image.png

快排

image.png

  1. //选取Pivot:通过位运算获取数组长度的1/7的近似值(位运算无法精确表示1/7)
  2. int seventh = (length >> 3) + (length >> 6) + 1;
  3. //获取数组中间位置左右1/7、2/7处的索引(e1、e2、e4、e5)
  4. int e3 = (left + right) >>> 1;
  5. int e2 = e3 - seventh;
  6. int e1 = e2 - seventh;
  7. int e4 = e3 + seventh;
  8. int e5 = e4 + seventh;
  9. //对e1-e5进行插入排序
  10. if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
  11. if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t;
  12. if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
  13. }
  14. if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t;
  15. if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
  16. if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
  17. }
  18. }
  19. if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t;
  20. if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
  21. if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
  22. if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
  23. }
  24. }
  25. }
  26. int less = left;
  27. int great = right;
  28. //5个元素没有相同的,就以e2、e4作为双枢轴
  29. if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
  30. int pivot1 = a[e2];
  31. int pivot2 = a[e4];
  32. a[e2] = a[left];
  33. a[e4] = a[right];
  34. //使得less左边元素都小于pivot1,great元素右边都小于povot2
  35. while (a[++less] < pivot1);
  36. while (a[--great] > pivot2);
  37. //开始排序,对less和great之间的元素排序,达到下图的效果
  38. /*
  39. * Partitioning:
  40. *
  41. * left part center part right part
  42. * +--------------------------------------------------------------+
  43. * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
  44. * +--------------------------------------------------------------+
  45. * ^ ^ ^
  46. * | | |
  47. * less k great
  48. *
  49. * Invariants:
  50. *
  51. * all in (left, less) < pivot1
  52. * pivot1 <= all in [less, k) <= pivot2
  53. * all in (great, right) > pivot2
  54. *
  55. * Pointer k is the first index of ?-part.
  56. */
  57. outer:
  58. for (int k = less - 1; ++k <= great; ) {
  59. int ak = a[k];
  60. if (ak < pivot1) {
  61. //ak跟a[less]交换
  62. a[k] = a[less];
  63. a[less] = ak;
  64. ++less;
  65. } else if (ak > pivot2) {
  66. //如果great大于pivot2,great继续往左边移动
  67. while (a[great] > pivot2) {
  68. if (great-- == k) {
  69. break outer;
  70. }
  71. }
  72. if (a[great] < pivot1) {
  73. //great小于pivot1,将great移到less的位置
  74. a[k] = a[less];
  75. a[less] = a[great];
  76. ++less;
  77. } else {
  78. // pivot1 <= a[great] <= pivot2,将great赋值到k的位置
  79. a[k] = a[great];
  80. }
  81. //ak跟a[great]交换
  82. a[great] = ak;
  83. --great;
  84. }
  85. }
  86. // 定位pivot1和pivot2的位置
  87. a[left] = a[less - 1]; a[less - 1] = pivot1;
  88. a[right] = a[great + 1]; a[great + 1] = pivot2;
  89. // Sort left and right parts recursively, excluding known pivots
  90. sort(a, left, less - 2, leftmost);
  91. sort(a, great + 2, right, false);
  92. /*
  93. * If center part is too large (comprises > 4/7 of the array),
  94. * swap internal pivot values to ends.
  95. */
  96. if (less < e1 && e5 < great) {
  97. /*
  98. * Skip elements, which are equal to pivot values.
  99. */
  100. while (a[less] == pivot1) {
  101. ++less;
  102. }
  103. while (a[great] == pivot2) {
  104. --great;
  105. }
  106. /*
  107. * Partitioning:
  108. *
  109. * left part center part right part
  110. * +----------------------------------------------------------+
  111. * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
  112. * +----------------------------------------------------------+
  113. * ^ ^ ^
  114. * | | |
  115. * less k great
  116. *
  117. * Invariants:
  118. *
  119. * all in (*, less) == pivot1
  120. * pivot1 < all in [less, k) < pivot2
  121. * all in (great, *) == pivot2
  122. *
  123. * Pointer k is the first index of ?-part.
  124. */
  125. outer:
  126. for (int k = less - 1; ++k <= great; ) {
  127. int ak = a[k];
  128. if (ak == pivot1) { // Move a[k] to left part
  129. a[k] = a[less];
  130. a[less] = ak;
  131. ++less;
  132. } else if (ak == pivot2) { // Move a[k] to right part
  133. while (a[great] == pivot2) {
  134. if (great-- == k) {
  135. break outer;
  136. }
  137. }
  138. if (a[great] == pivot1) { // a[great] < pivot2
  139. a[k] = a[less];
  140. /*
  141. * Even though a[great] equals to pivot1, the
  142. * assignment a[less] = pivot1 may be incorrect,
  143. * if a[great] and pivot1 are floating-point zeros
  144. * of different signs. Therefore in float and
  145. * double sorting methods we have to use more
  146. * accurate assignment a[less] = a[great].
  147. */
  148. a[less] = pivot1;
  149. ++less;
  150. } else { // pivot1 < a[great] < pivot2
  151. a[k] = a[great];
  152. }
  153. a[great] = ak;
  154. --great;
  155. }
  156. }
  157. }
  158. // Sort center part recursively
  159. sort(a, less, great, false);
  160. } else { // Partitioning with one pivot
  161. //存在相同元素,就使用e3作为枢轴
  162. int pivot = a[e3];
  163. /*
  164. * Partitioning degenerates to the traditional 3-way
  165. * (or "Dutch National Flag") schema:
  166. *
  167. * left part center part right part
  168. * +-------------------------------------------------+
  169. * | < pivot | == pivot | ? | > pivot |
  170. * +-------------------------------------------------+
  171. * ^ ^ ^
  172. * | | |
  173. * less k great
  174. *
  175. * Invariants:
  176. *
  177. * all in (left, less) < pivot
  178. * all in [less, k) == pivot
  179. * all in (great, right) > pivot
  180. *
  181. * Pointer k is the first index of ?-part.
  182. */
  183. for (int k = less; k <= great; ++k) {
  184. if (a[k] == pivot) {
  185. continue;
  186. }
  187. int ak = a[k];
  188. //小于pivot,直接将k与less交换
  189. if (ak < pivot) {
  190. a[k] = a[less];
  191. a[less] = ak;
  192. ++less;
  193. } else {
  194. //开始反向从great遍历,如果great元素>枢轴,无需交换,great向前移动
  195. while (a[great] > pivot) {
  196. --great;
  197. }
  198. //great元素小于pviot,就跟先将less复制到k指向的位置(此时k位置原本的元素由ak保存),然后将great元素复制到less,less++
  199. //即,less-->k, great-->less交换,k -->great
  200. if (a[great] < pivot) { // a[great] <= pivot
  201. a[k] = a[less];
  202. a[less] = a[great];
  203. ++less;
  204. } else {
  205. //如果great等于pivot,将pivot的值直接复制到k指向的位置
  206. a[k] = pivot;
  207. }
  208. //将k的元素复制到great
  209. a[great] = ak;
  210. --great;
  211. }
  212. }
  213. /*
  214. * Sort left and right parts recursively.
  215. * All elements from center part are equal
  216. * and, therefore, already sorted.
  217. */
  218. sort(a, left, less - 1, leftmost);
  219. sort(a, great + 1, right, false);
  220. }

高度结构化判断

  1. // Check if the array is nearly sorted
  2. // k的值表示多个升序序列尾部索引,count表示升降序改变次数
  3. for (int k = left; k < right; run[count] = k) {
  4. if (a[k] < a[k + 1]) {
  5. //升序
  6. while (++k <= right && a[k - 1] <= a[k]);
  7. } else if (a[k] > a[k + 1]) {
  8. //降序
  9. while (++k <= right && a[k - 1] >= a[k]);
  10. //翻转序列,将降序变为升序
  11. for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
  12. int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
  13. }
  14. } else {
  15. //相同元素超过33,使用快排
  16. for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
  17. if (--m == 0) {
  18. sort(a, left, right, true);
  19. return;
  20. }
  21. }
  22. }
  23. //当遍历过程中发现变化次数高于33次时,直接使用快排
  24. if (++count == MAX_RUN_COUNT) {
  25. sort(a, left, right, true);
  26. return;
  27. }
  28. }

T[]排序

参见容器排序:https://www.yuque.com/zhicizhongnian/nr4160/huyv1h