【Java源码】理解Java中Comparator接⼝中的返回值1,-1,0⽂章⽬录
写法
升序标准写法(官⽅写法),jdk官⽅默认是升序:
<return-1//意思就是
=return0
>return1
官⽅的源码就是基于这个写的;可以理解为硬性规定。也就是说,排序是由这三个参数同时决定的。
如果要降序就必须完全相反:
<return1
=return0
>return-1
测试代码
public class TestCompare {
public static void main(String[] args){
List<Integer> list =new ArrayList<>();
list.add(1);
list.add(2);
list.add(6);
list.add(5);
list.add(8);
list.add(8);
list.add(4);
Collections.sort(list,new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2){
//下⾯这么写,结果是升序
/*如果保持这个顺序就返回-1,交换顺序就返回1,什么都不做就返回0;所以升序的话如果o1<o2,就返回-1。*/
//if (o1 < o2 ) {
// return -1;
//}else if (o1 > o2) {
// return 1;
//}
//return 0;
//下⾯这么写,结果是降序
/*如果保持这个顺序就返回-1,交换顺序就返回1,什么都不做就返回0;所以升序的话如果o1<o2,就返回-1。*/
if(o1 < o2){
return1;
}else if(o1 > o2){
return-1;
}
return0;
}
});
System.out.println(list);
}
}
测试结果:升序
测试结果:降序
为什么呢?这个只能通过源码的⽅式去看了
降序源码分析
1. 第⼀步进⼊源码Collections类中到sort⽅法
@SuppressWarnings({"unchecked","rawtypes"})
public static<T>void sort(List<T> list, Comparator<?super T> c){
list.sort(c);
}
2. 进⼊上⾯list.sort(c)源码:
@SuppressWarnings({"unchecked","rawtypes"})
default void sort(Comparator<?super E> c){
Object[] a =Array();
// 主要看到这⾥
Arrays.sort(a,(Comparator) c);
ListIterator<E> i =this.listIterator();
for(Object e : a){
<();
i.set((E) e);
}
}
3. 进⼊上⾯Arrays.sort(a, (Comparator) c);⽅法:
public static<T>void sort(T[] a, Comparator<?super T> c){
if(c == null){
sort(a);
}else{
if(LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
/
/接下来会⾛这个⽅法,上⾯不会⾛;
//未来jdk会弃⽤legacyMergeSort⽅法。
TimSort.sort(a,0, a.length, c, null,0,0);
}
}
4. 进⼊上⾯的 TimSort.sort(a, 0, a.length, c, null, 0, 0);这个⽅法很长,我先贴出主要核⼼的:
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;
}
/**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
TimSort<T> ts =new TimSort<>(a, c, work, workBase, workLen);
int minRun =minRunLength(nRemaining);
do{
// Identify next run
int runLen =countRunAndMakeAscending(a, lo, hi, c);
// If run is short, extend to min(minRun, nRemaining)
if(runLen < minRun){
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen, c);
runLen = force;
}
/
/ Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
// Advance to find next run
lo += runLen;
nRemaining -= runLen;
}while(nRemaining !=0);
// Merge all remaining runs to complete sort
assert lo == hi;
assert ts.stackSize ==1;
}
5. 进⼊上⾯的 countRunAndMakeAscending⽅法
private static<T>int countRunAndMakeAscending(T[] a,int lo,int hi, Comparator<?super T> c){
// lo 是数组起始位置也就是 0
assert lo < hi;
// runHi = 1,这个值会随着循环⽽改变,表⽰当前元素的位置
int runHi = lo +1;
// hi是数组长度
if(runHi == hi)
return1;
// Find end of run, and reverse range if descending
/
/这⾥cpare()调⽤就是我们重写的⽅法
if(cpare(a[runHi++], a[lo])<0){// Descending
while(runHi < hi && cpare(a[runHi], a[runHi -1])<0)
runHi++;
reverseRange(a, lo, runHi);
}else{
// Ascending -- 英⽂的注释,默认是升序;不⽤管这个注释
while(runHi < hi && cpare(a[runHi], a[runHi -1])>=0)
runHi++;
}
return runHi - lo;
}
这个⽅法就是关键;
1 2 6 5 8 8 4
其中
if (o1 < o2) {// 01 ⼩于 02 交换位置
return 1;
} else if (o1 > o2) {// 不交换位置
return -1;
}
java中index是什么意思return 0;//什么都不做
if (cpare(a[runHi++], a[lo]) < 0)— 这句代码,对我的测试代码⽽⾔:if (cpare(2, 1) < 0)中cpare(2,1)得到的就是-1。接着就是执⾏:
while(runHi < hi && cpare(a[runHi], a[runHi -1])<0)
runHi++;
reverseRange(a, lo, runHi);
while (runHi < hi && cpare(a[runHi], a[runHi - 1]) < 0)中 cpare(a[runHi], a[runHi - 1]) < 0)就是 cpare(6, 2) < 0),⽽ cpare(6, 2)返回的是-1,所以会接着循环执⾏,runHi++后,此时runHi=2。就我的测试代码就会去判断cpare(5, 6),其返回的是1,循环结束,接着执⾏r everseRange(a, lo, runHi);。这是个反转⽅法
private static void reverseRange(Object[] a,int lo,int hi){
hi--;
while(lo < hi){
Object t = a[lo];
a[lo++]= a[hi];
a[hi--]= t;
}
}
效果就是:
数组:1 2 6 5 8 8 4
反转后:6 2 1 5 8 8 4
可以看出,前⾯三个数字顺序已经好了,后⾯的5 8 8 4,会在执⾏binarySort(a, lo, hi, lo + initRunLen, c);这个⽅法时来进⾏⼆分插⼊排序。
6. 执⾏binarySort(a, lo, hi, lo + initRunLen, c)⽅法:
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){
//这⾥相当于除以2
int mid =(left + right)>>>1;
if(cpare(pivot, a[mid])<0)
right = mid;
else
left = mid +1;
}
//当left等于right时,就说明到位置了。
/
/assert是断⾔,要是为false会直接报错
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){
case2: a[left +2]= a[left +1];
case1: a[left +1]= a[left];
break;
//要是移动的位数⼤于2,就执⾏如下⽅法;
default: System.arraycopy(a, left, a, left +1, n);
}
a[left]= pivot;
}
}
例⼦中的数组:
6 2 1 5 8 8 4
//循环执⾏binarySort⽅法后,
//会依次把 5 8 8 4 插⼊到相应的位置
//最终的结果为:
8 8 6 5 4 2 1
升序源码分析
升序jdk默认的顺序,例⼦:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论