TimeSort的sort部分源码

今天进行开发时,需要将集合进行排序。 走代码时,看到的 TimeSort 类型。
通过 ArrayList的 sort() 方法进入到 TimSort的Sort() 方法,记录部分逻辑。

a – 数组
lo – 数组第一个元素下角标
hi – 数组最后一个元素下角标 (值+1

static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c, T[] work, int workBase, int workLen) { //此处断言,处理入参不和规的情况 assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; // ho 排序从哪个index之开始,hi 到哪结束 int nRemaining = hi - lo; // 一共有几个 if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges // MIN_MERGE 为32 ,也就说,参与排序的元素数量小于32个,不使用 分合方式 进行排序 if (nRemaining < MIN_MERGE) { // 返回一个值,看 ② countRunAndMakeAscending 方法 int initRunLen = countRunAndMakeAscending(a, lo, hi, c); // 进行排序 // 如果 c == null 按照二进制排序 // 如果 c != null 按照 c 进行排序 // 看 ③ binarySort 方法 // 可以看做 从 (lo + initRunLen)位置开始,进行位置调整,直到 hi 的位置 binarySort(a, lo, hi, lo + initRunLen, c); return; } // 以上代码为 元素数量 < 32,情况下所走逻辑 /** * 如果元素数量太多,通过 分合方式 进行排序 */ TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen); // 获取 单个区不超过32为的最大中间值 int minRun = minRunLength(nRemaining); do { // 返回一个值,看 ② countRunAndMakeAscending 方法。runLen 排序正确的数量 int runLen = countRunAndMakeAscending(a, lo, hi, c); // runLen < minRun 表示第一个排序区间的内容并不是排序正确的 if (runLen < minRun) { int force = nRemaining <= minRun ? nRemaining : minRun; // 看 ③ binarySort 方法 // 可以看做 从 (lo + runLen)位置开始,进行位置调整,直到 (lo + force) 的位置 binarySort(a, lo, lo + force, lo + runLen, c); // 此时排序正确的数值为 force 个 runLen = force; } // Push run onto pending-run stack, and maybe merge // 进行代码合并,分段进行合并,以下不做细看 ts.pushRun(lo, runLen); ts.mergeCollapse(); // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse(); assert ts.stackSize == 1; }
② countRunAndMakeAscending 方法,返回initRunLen 用于确认现数组中有几个值是排序正确的
private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi, Comparator<? super T> c) { assert lo < hi; int runHi = lo + 1; if (runHi == hi) return 1; // Find end of run, and reverse range if descending // 通过 前两个元素 来判断数组按照正序是倒序 if (c.compare(a[runHi++], a[lo]) < 0) { // Descending while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) runHi++; // 进行倒序,是将数值两边的值位置进行调换 reverseRange(a, lo, runHi); } else { // Ascending while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0) runHi++; } // 上面方法的作用: // ① 判断数组是按正序还是倒序,如果是倒序,进行位置调整,如果是正序,不进行位置调整 // ② 确认当前数组排序正常的位置 // runHi 为 排序正常的最后一个元素下角标 // runHi - lo 为 第一个值 return runHi - lo; }
③ binarySort 方法,通过二分法确定元素位置,进行位置替换,从而达到排序的效果
private static <T> void binarySort(T[] a, int lo, int hi, int start, Comparator<? super T> c) { // start 为 ② 返回的 intRunLen,排序的开端 assert lo <= start && start <= hi; if (start == lo) start++; for ( ; start < hi; start++) { T pivot = a[start]; // Set left (and right) to the index where a[start] (pivot) belongs int left = lo; int right = start; assert left <= right; /* * Invariants: 期望值 * pivot >= all in [lo, left). * pivot < all in [right, start). */ while (left < right) { int mid = (left + right) >>> 1; if (c.compare(pivot, a[mid]) < 0) right = mid; else left = mid + 1; } // 以上代码的作用是 通过二分法的方式确认pivot 应该与那个值进行互换 // assert 当 left == right 可以确认去位置 assert left == right; /* * The invariants still hold: pivot >= all in [lo, left) and * pivot < all in [left, start), so pivot belongs at left. Note * that if there are elements equal to pivot, left points to the * first slot after them -- that's why this sort is stable. * Slide elements over to make room for pivot. */ // The number of elements to move // n 为 pivot 与 互换元素 之间的位置,通过距离超过2位,通过 复制数组实现 int n = start - left; // Switch is just an optimization for arraycopy in default case switch (n) { case 2: a[left + 2] = a[left + 1]; case 1: a[left + 1] = a[left]; break; default: System.arraycopy(a, left, a, left + 1, n); } a[left] = pivot; }

__EOF__

本文作者之士咖啡
本文链接https://www.cnblogs.com/zz-1q/p/17394166.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   之士咖啡  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示