java比较器Comparator原理笔记
程序员文章站
2022-07-10 17:51:07
新手的Comparator原理分析,底层代码追踪,底层排序应该是二分查找实现的插入排序...
部分为个人猜测,因为没太多时间详细分析,有误希望大佬来指正。
以下是代码追踪。
Collections.sort(list, new MyComparator());
//MyComparator为实现了Comparator接口的比较器,list为一个Arraylist数组。
//这里底层调用的是Arraylist.sort,如下
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
//Arraylist.sort()方法里又调用了 Arrays.sort,如下
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) {
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}
//最终调用的是TimSort.sort,这是最核心的调用方法
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;
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
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
经过上面代码追踪可以发现最核心的代码TimSort.sort方法,如下
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;
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
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
TimSort.sort方法里有两个核心方法
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);//负责查出数组一直到第几个数为止有序。(ps:为后面start做准备,并且减少无用的比较。)
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++;
}
return runHi - lo;
}
binarySort(a, lo, hi, lo + initRunLen, c);//对数组进行排序。
/*1、从start开始,pivot=array[start],对每个数值进行二分查找法,二分查找的数组范围是已经有序的数组,
*2、当查到最适合的位置index时,将start-1到index范围内的数组值向后移动一位(变成index+1~start),把pivot的值赋予array[index]。实现交换
*3、start++然后执行1,2步骤直到数组结束。
*/
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
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;
}
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.
*/
int n = start - left; // The number of elements to move
// 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;
}
}
综上分析:可推测Comparator实现比较器的底层是使用二分查找法得出数值的实际位置,比较方面是调用c.compare。
本文地址:https://blog.csdn.net/zero_cctv/article/details/109640173
推荐阅读
-
Java 中Comparable和Comparator区别比较
-
java比较器Comparable接口与Comaprator接口的深入分析
-
java比较器Comparable接口与Comaprator接口的深入分析
-
java控件使用方法(java监听器的原理与实现)
-
java控件使用方法(java监听器的原理与实现)
-
Java web拦截器inteceptor原理及应用详解
-
Java 比较器的用法
-
20.7.17 笔记算数运算符 复合运算符重载 比较运算重载 多态 设计原则 类的单一职责 依赖倒置 组合复用原则 里氏替换 迪米特法则 矩阵转置原理
-
Java垃圾回收器的工作原理
-
Collections包装类和Comparator比较器