6256abe51224ca18695fe296842af76bbfc9e49d9aff77788d24f4c0cb4aa02506cfd9b228e5edbc3b0f72a03cf495899a56fc8628363436e88e4ef975b2c7 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. var DEFAULT_MIN_MERGE = 32;
  2. var DEFAULT_MIN_GALLOPING = 7;
  3. var DEFAULT_TMP_STORAGE_LENGTH = 256;
  4. function minRunLength(n) {
  5. var r = 0;
  6. while (n >= DEFAULT_MIN_MERGE) {
  7. r |= n & 1;
  8. n >>= 1;
  9. }
  10. return n + r;
  11. }
  12. function makeAscendingRun(array, lo, hi, compare) {
  13. var runHi = lo + 1;
  14. if (runHi === hi) {
  15. return 1;
  16. }
  17. if (compare(array[runHi++], array[lo]) < 0) {
  18. while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
  19. runHi++;
  20. }
  21. reverseRun(array, lo, runHi);
  22. }
  23. else {
  24. while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
  25. runHi++;
  26. }
  27. }
  28. return runHi - lo;
  29. }
  30. function reverseRun(array, lo, hi) {
  31. hi--;
  32. while (lo < hi) {
  33. var t = array[lo];
  34. array[lo++] = array[hi];
  35. array[hi--] = t;
  36. }
  37. }
  38. function binaryInsertionSort(array, lo, hi, start, compare) {
  39. if (start === lo) {
  40. start++;
  41. }
  42. for (; start < hi; start++) {
  43. var pivot = array[start];
  44. var left = lo;
  45. var right = start;
  46. var mid;
  47. while (left < right) {
  48. mid = left + right >>> 1;
  49. if (compare(pivot, array[mid]) < 0) {
  50. right = mid;
  51. }
  52. else {
  53. left = mid + 1;
  54. }
  55. }
  56. var n = start - left;
  57. switch (n) {
  58. case 3:
  59. array[left + 3] = array[left + 2];
  60. case 2:
  61. array[left + 2] = array[left + 1];
  62. case 1:
  63. array[left + 1] = array[left];
  64. break;
  65. default:
  66. while (n > 0) {
  67. array[left + n] = array[left + n - 1];
  68. n--;
  69. }
  70. }
  71. array[left] = pivot;
  72. }
  73. }
  74. function gallopLeft(value, array, start, length, hint, compare) {
  75. var lastOffset = 0;
  76. var maxOffset = 0;
  77. var offset = 1;
  78. if (compare(value, array[start + hint]) > 0) {
  79. maxOffset = length - hint;
  80. while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
  81. lastOffset = offset;
  82. offset = (offset << 1) + 1;
  83. if (offset <= 0) {
  84. offset = maxOffset;
  85. }
  86. }
  87. if (offset > maxOffset) {
  88. offset = maxOffset;
  89. }
  90. lastOffset += hint;
  91. offset += hint;
  92. }
  93. else {
  94. maxOffset = hint + 1;
  95. while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
  96. lastOffset = offset;
  97. offset = (offset << 1) + 1;
  98. if (offset <= 0) {
  99. offset = maxOffset;
  100. }
  101. }
  102. if (offset > maxOffset) {
  103. offset = maxOffset;
  104. }
  105. var tmp = lastOffset;
  106. lastOffset = hint - offset;
  107. offset = hint - tmp;
  108. }
  109. lastOffset++;
  110. while (lastOffset < offset) {
  111. var m = lastOffset + (offset - lastOffset >>> 1);
  112. if (compare(value, array[start + m]) > 0) {
  113. lastOffset = m + 1;
  114. }
  115. else {
  116. offset = m;
  117. }
  118. }
  119. return offset;
  120. }
  121. function gallopRight(value, array, start, length, hint, compare) {
  122. var lastOffset = 0;
  123. var maxOffset = 0;
  124. var offset = 1;
  125. if (compare(value, array[start + hint]) < 0) {
  126. maxOffset = hint + 1;
  127. while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
  128. lastOffset = offset;
  129. offset = (offset << 1) + 1;
  130. if (offset <= 0) {
  131. offset = maxOffset;
  132. }
  133. }
  134. if (offset > maxOffset) {
  135. offset = maxOffset;
  136. }
  137. var tmp = lastOffset;
  138. lastOffset = hint - offset;
  139. offset = hint - tmp;
  140. }
  141. else {
  142. maxOffset = length - hint;
  143. while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
  144. lastOffset = offset;
  145. offset = (offset << 1) + 1;
  146. if (offset <= 0) {
  147. offset = maxOffset;
  148. }
  149. }
  150. if (offset > maxOffset) {
  151. offset = maxOffset;
  152. }
  153. lastOffset += hint;
  154. offset += hint;
  155. }
  156. lastOffset++;
  157. while (lastOffset < offset) {
  158. var m = lastOffset + (offset - lastOffset >>> 1);
  159. if (compare(value, array[start + m]) < 0) {
  160. offset = m;
  161. }
  162. else {
  163. lastOffset = m + 1;
  164. }
  165. }
  166. return offset;
  167. }
  168. function TimSort(array, compare) {
  169. var minGallop = DEFAULT_MIN_GALLOPING;
  170. var length = 0;
  171. var tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
  172. var stackLength = 0;
  173. var runStart;
  174. var runLength;
  175. var stackSize = 0;
  176. length = array.length;
  177. if (length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
  178. tmpStorageLength = length >>> 1;
  179. }
  180. var tmp = [];
  181. stackLength = length < 120 ? 5 : length < 1542 ? 10 : length < 119151 ? 19 : 40;
  182. runStart = [];
  183. runLength = [];
  184. function pushRun(_runStart, _runLength) {
  185. runStart[stackSize] = _runStart;
  186. runLength[stackSize] = _runLength;
  187. stackSize += 1;
  188. }
  189. function mergeRuns() {
  190. while (stackSize > 1) {
  191. var n = stackSize - 2;
  192. if ((n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1])
  193. || (n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1])) {
  194. if (runLength[n - 1] < runLength[n + 1]) {
  195. n--;
  196. }
  197. }
  198. else if (runLength[n] > runLength[n + 1]) {
  199. break;
  200. }
  201. mergeAt(n);
  202. }
  203. }
  204. function forceMergeRuns() {
  205. while (stackSize > 1) {
  206. var n = stackSize - 2;
  207. if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
  208. n--;
  209. }
  210. mergeAt(n);
  211. }
  212. }
  213. function mergeAt(i) {
  214. var start1 = runStart[i];
  215. var length1 = runLength[i];
  216. var start2 = runStart[i + 1];
  217. var length2 = runLength[i + 1];
  218. runLength[i] = length1 + length2;
  219. if (i === stackSize - 3) {
  220. runStart[i + 1] = runStart[i + 2];
  221. runLength[i + 1] = runLength[i + 2];
  222. }
  223. stackSize--;
  224. var k = gallopRight(array[start2], array, start1, length1, 0, compare);
  225. start1 += k;
  226. length1 -= k;
  227. if (length1 === 0) {
  228. return;
  229. }
  230. length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
  231. if (length2 === 0) {
  232. return;
  233. }
  234. if (length1 <= length2) {
  235. mergeLow(start1, length1, start2, length2);
  236. }
  237. else {
  238. mergeHigh(start1, length1, start2, length2);
  239. }
  240. }
  241. function mergeLow(start1, length1, start2, length2) {
  242. var i = 0;
  243. for (i = 0; i < length1; i++) {
  244. tmp[i] = array[start1 + i];
  245. }
  246. var cursor1 = 0;
  247. var cursor2 = start2;
  248. var dest = start1;
  249. array[dest++] = array[cursor2++];
  250. if (--length2 === 0) {
  251. for (i = 0; i < length1; i++) {
  252. array[dest + i] = tmp[cursor1 + i];
  253. }
  254. return;
  255. }
  256. if (length1 === 1) {
  257. for (i = 0; i < length2; i++) {
  258. array[dest + i] = array[cursor2 + i];
  259. }
  260. array[dest + length2] = tmp[cursor1];
  261. return;
  262. }
  263. var _minGallop = minGallop;
  264. var count1;
  265. var count2;
  266. var exit;
  267. while (1) {
  268. count1 = 0;
  269. count2 = 0;
  270. exit = false;
  271. do {
  272. if (compare(array[cursor2], tmp[cursor1]) < 0) {
  273. array[dest++] = array[cursor2++];
  274. count2++;
  275. count1 = 0;
  276. if (--length2 === 0) {
  277. exit = true;
  278. break;
  279. }
  280. }
  281. else {
  282. array[dest++] = tmp[cursor1++];
  283. count1++;
  284. count2 = 0;
  285. if (--length1 === 1) {
  286. exit = true;
  287. break;
  288. }
  289. }
  290. } while ((count1 | count2) < _minGallop);
  291. if (exit) {
  292. break;
  293. }
  294. do {
  295. count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
  296. if (count1 !== 0) {
  297. for (i = 0; i < count1; i++) {
  298. array[dest + i] = tmp[cursor1 + i];
  299. }
  300. dest += count1;
  301. cursor1 += count1;
  302. length1 -= count1;
  303. if (length1 <= 1) {
  304. exit = true;
  305. break;
  306. }
  307. }
  308. array[dest++] = array[cursor2++];
  309. if (--length2 === 0) {
  310. exit = true;
  311. break;
  312. }
  313. count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
  314. if (count2 !== 0) {
  315. for (i = 0; i < count2; i++) {
  316. array[dest + i] = array[cursor2 + i];
  317. }
  318. dest += count2;
  319. cursor2 += count2;
  320. length2 -= count2;
  321. if (length2 === 0) {
  322. exit = true;
  323. break;
  324. }
  325. }
  326. array[dest++] = tmp[cursor1++];
  327. if (--length1 === 1) {
  328. exit = true;
  329. break;
  330. }
  331. _minGallop--;
  332. } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
  333. if (exit) {
  334. break;
  335. }
  336. if (_minGallop < 0) {
  337. _minGallop = 0;
  338. }
  339. _minGallop += 2;
  340. }
  341. minGallop = _minGallop;
  342. minGallop < 1 && (minGallop = 1);
  343. if (length1 === 1) {
  344. for (i = 0; i < length2; i++) {
  345. array[dest + i] = array[cursor2 + i];
  346. }
  347. array[dest + length2] = tmp[cursor1];
  348. }
  349. else if (length1 === 0) {
  350. throw new Error();
  351. }
  352. else {
  353. for (i = 0; i < length1; i++) {
  354. array[dest + i] = tmp[cursor1 + i];
  355. }
  356. }
  357. }
  358. function mergeHigh(start1, length1, start2, length2) {
  359. var i = 0;
  360. for (i = 0; i < length2; i++) {
  361. tmp[i] = array[start2 + i];
  362. }
  363. var cursor1 = start1 + length1 - 1;
  364. var cursor2 = length2 - 1;
  365. var dest = start2 + length2 - 1;
  366. var customCursor = 0;
  367. var customDest = 0;
  368. array[dest--] = array[cursor1--];
  369. if (--length1 === 0) {
  370. customCursor = dest - (length2 - 1);
  371. for (i = 0; i < length2; i++) {
  372. array[customCursor + i] = tmp[i];
  373. }
  374. return;
  375. }
  376. if (length2 === 1) {
  377. dest -= length1;
  378. cursor1 -= length1;
  379. customDest = dest + 1;
  380. customCursor = cursor1 + 1;
  381. for (i = length1 - 1; i >= 0; i--) {
  382. array[customDest + i] = array[customCursor + i];
  383. }
  384. array[dest] = tmp[cursor2];
  385. return;
  386. }
  387. var _minGallop = minGallop;
  388. while (true) {
  389. var count1 = 0;
  390. var count2 = 0;
  391. var exit = false;
  392. do {
  393. if (compare(tmp[cursor2], array[cursor1]) < 0) {
  394. array[dest--] = array[cursor1--];
  395. count1++;
  396. count2 = 0;
  397. if (--length1 === 0) {
  398. exit = true;
  399. break;
  400. }
  401. }
  402. else {
  403. array[dest--] = tmp[cursor2--];
  404. count2++;
  405. count1 = 0;
  406. if (--length2 === 1) {
  407. exit = true;
  408. break;
  409. }
  410. }
  411. } while ((count1 | count2) < _minGallop);
  412. if (exit) {
  413. break;
  414. }
  415. do {
  416. count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
  417. if (count1 !== 0) {
  418. dest -= count1;
  419. cursor1 -= count1;
  420. length1 -= count1;
  421. customDest = dest + 1;
  422. customCursor = cursor1 + 1;
  423. for (i = count1 - 1; i >= 0; i--) {
  424. array[customDest + i] = array[customCursor + i];
  425. }
  426. if (length1 === 0) {
  427. exit = true;
  428. break;
  429. }
  430. }
  431. array[dest--] = tmp[cursor2--];
  432. if (--length2 === 1) {
  433. exit = true;
  434. break;
  435. }
  436. count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
  437. if (count2 !== 0) {
  438. dest -= count2;
  439. cursor2 -= count2;
  440. length2 -= count2;
  441. customDest = dest + 1;
  442. customCursor = cursor2 + 1;
  443. for (i = 0; i < count2; i++) {
  444. array[customDest + i] = tmp[customCursor + i];
  445. }
  446. if (length2 <= 1) {
  447. exit = true;
  448. break;
  449. }
  450. }
  451. array[dest--] = array[cursor1--];
  452. if (--length1 === 0) {
  453. exit = true;
  454. break;
  455. }
  456. _minGallop--;
  457. } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
  458. if (exit) {
  459. break;
  460. }
  461. if (_minGallop < 0) {
  462. _minGallop = 0;
  463. }
  464. _minGallop += 2;
  465. }
  466. minGallop = _minGallop;
  467. if (minGallop < 1) {
  468. minGallop = 1;
  469. }
  470. if (length2 === 1) {
  471. dest -= length1;
  472. cursor1 -= length1;
  473. customDest = dest + 1;
  474. customCursor = cursor1 + 1;
  475. for (i = length1 - 1; i >= 0; i--) {
  476. array[customDest + i] = array[customCursor + i];
  477. }
  478. array[dest] = tmp[cursor2];
  479. }
  480. else if (length2 === 0) {
  481. throw new Error();
  482. }
  483. else {
  484. customCursor = dest - (length2 - 1);
  485. for (i = 0; i < length2; i++) {
  486. array[customCursor + i] = tmp[i];
  487. }
  488. }
  489. }
  490. return {
  491. mergeRuns: mergeRuns,
  492. forceMergeRuns: forceMergeRuns,
  493. pushRun: pushRun
  494. };
  495. }
  496. export default function sort(array, compare, lo, hi) {
  497. if (!lo) {
  498. lo = 0;
  499. }
  500. if (!hi) {
  501. hi = array.length;
  502. }
  503. var remaining = hi - lo;
  504. if (remaining < 2) {
  505. return;
  506. }
  507. var runLength = 0;
  508. if (remaining < DEFAULT_MIN_MERGE) {
  509. runLength = makeAscendingRun(array, lo, hi, compare);
  510. binaryInsertionSort(array, lo, hi, lo + runLength, compare);
  511. return;
  512. }
  513. var ts = TimSort(array, compare);
  514. var minRun = minRunLength(remaining);
  515. do {
  516. runLength = makeAscendingRun(array, lo, hi, compare);
  517. if (runLength < minRun) {
  518. var force = remaining;
  519. if (force > minRun) {
  520. force = minRun;
  521. }
  522. binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
  523. runLength = force;
  524. }
  525. ts.pushRun(lo, runLength);
  526. ts.mergeRuns();
  527. remaining -= runLength;
  528. lo += runLength;
  529. } while (remaining !== 0);
  530. ts.forceMergeRuns();
  531. }