首页 > 编程知识 正文

compareto方法返回值(java compareto 返回值_Java comparable接口及compareTo返回值所决定的升序降序问题)

时间:2023-05-03 22:28:16 阅读:123905 作者:4257

在学习java基础时,我知道基本数据类型数组可以直接动员和输出Arrays类的静态sort方法。

示例: int iarr [ ]={ 1,2,4,6 }; Arrays.sort(Iarr ); 然后以for循环输出.

但是,如果我们是对象数组,则对象所在的类必须实现comparable接口,编写其compareTo方法,并具有表示升序和降序的不同返回值。

但是,我怀疑为什么对象数组必须调用Arrays.sort来实现comparable接口。 而且,compareTo的返回值到底意味着什么呢? 另外,如何决定排列的升序和降序呢?

带着这样的疑问,我自己写了一个简单的例子。 然后进行调试,跟进源代码,终于有发现的边缘了。 然后,我会和大家分享我自己的理解

有关如何访问源代码以及如何查看源代码中变量的信息,我在一个博客中做了补充,有时间再看一下。

以下代码://Test类包测试;

publicclasstestimplementscomparable

{

int age=0;

字符串名称;

公共测试(intage,字符串名称) )。

{

super (;

this.age=age;

Name=name;

}

公共输入比较到(测试) )。

{

if(this.ageo.age ) )。

返回1;

else返回- 1;

}

公共字符串tostring (

{

返回age name;

}

}

//TestDemo类包测试;

import java.util.Arrays;

公共类测试演示

{

publicstaticvoidmain (字符串args [ ] ) ) ) ) )。

{

Test t[]={

新测试(6,' paul )、

新测试(5、' ss )、

新测试(2、' kk )、

新测试(3,' tt )、

新测试(1,' ii ' ) ) ) )。

(;

Arrays.sort(t;

for(intI=0; I

{

system.out.println(t[I];

}

}

}

然后添加断点并调试

首先方法1:Arrays.class中的sort (转到方法

公共服务语音(对象[ ] a ) )。

{

注册合并.用户请求(if )。

Legacymergesort(a;

Else

comparabletimsort.sort(a,0,a.length,null,0,0 );

}

然后转至方法2:ComparableTimSort.class中的sort ()方法

staticvoidsort(object[]a,int lo,int hi,Object[] work,int workBase,int workLen ) )。

{

资产a!=null lo=0 lo=hi hi=a.length;

int nRemaining=hi - lo;

if (排序2 )返回;

//arraysofsize0and1arealwayssorted

//If array is small,do a 'mini-TimSort' with no merges

if (nRemaining MIN_MERGE )

{

intinitrunlen=countrunandmakeascending (a,lo,hi );

二进制sort (a,lo,hi,lo initRunLen );

返回;

}

comparabletimsortts=newcomparabletimsort (a,work,workBase,workL

en);

int minRun = minRunLength(nRemaining);

do {

// Identify next run

int runLen = countRunAndMakeAscending(a, lo, hi);

// 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);

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;

}

下一步进入:方法3:ComparableTimSort.class的countRunAndMakeAscending方法里面终于见到了我们的CompareTo方法

private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {

assert lo < hi;

int runHi = lo + 1;

if (runHi == hi)

return 1;

// Find end of run, and reverse range if descending

if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) {

while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)

runHi++;

//反转对象数组的lo~runHi-1部分,该方法也在ComparableTimSort.class中

reverseRange(a, lo, runHi);

} else {

while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)

runHi++;

}

return runHi - lo;

}

这里你应该终于明白了为什么一定要实现comparable接口中的compareTo方法了吧。

如何你没有实现,那么通过接口去找compareTo方法肯定会报错啊(因为这时候找不到compareTo方法,未定义)

结合Test类中的compareTo方法,当this.age

所以进入while循环,直到 a[runHi]).compareTo(a[runHi - 1])>=0时结束循环,后反转对象数组的lo~runHi-1部分

(ComparableTimSort.class)reverseRange(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;

}

}

此时经过反转后数组变为了 2, 5, 6, 3, 1(这里没有写name属性),也就是前面3个对象是有序的,升序接下来我们就进入了下一个方法(ComparableTimSort.class)

private static void binarySort(Object[] a, int lo, int hi, int start)

{

assert lo <= start && start <= hi;

if (start == lo) start++;

for ( ; start < hi; start++)

{

Comparable pivot = (Comparable) 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 (pivot.compareTo(a[mid]) < 0)

right = mid;

else

left = mid + 1;

}

assert left == right;

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;

}

}

我花了一点时间看了一下,就是C语言数据结构的二分排序法(也叫折半插入法,它是插入排序的一种改进版)

基本思想是:现将部分数组的部分元素变成一个有序的数组,后面的元素通过折半插入将它变成一个有序的数组。

例如前文:数组变成了2,5,6,3,1

则3插入前面有序的数组中,变成了 2,3,5,6,1

1在插入前面有序的数组中,变成了1,2,3,5,6

大家有时间可以去研究下。。这里不做详细说明。到了这里方法基本都跟进并介绍完了

输出结果:

1ii

2kk

3tt

5ss

6paul  升序。

那如何是降序呢?

修改Test类中的compareTo方法:

public int compareTo(Test o)

{

if (this.age > o.age)

return -1;

return 1;

}

将返回值调换就行了,输出结果:

6paul

5ss

3tt

2kk

1ii    降序

关于compareTo方法的实现及返回值以下的组合,譬如:

public int compareTo(Test o)

{

if (o.age > this.age){

return 1;

return -1;

}

public int compareTo(Test o)

{

if (o.age > this.age)

return -1;

return 1;

}

那他们到底是升序还是降序呢?自己结合源码可以去思考一下。

但是上面两种不建议写,因为容易混淆。推荐写最上面两种。。。

写了这么多 总结一下:

//升序

public int compareTo(Test o)

{

if (this.age>o.age ){

return 1;

return -1;

}

//降序

public int compareTo(Test o)

{

if (this.age > o.age)

return -1;

return 1;

}

我自己记忆的方法是:

大于号 返回1,正乘正为正,所以升序(可以把>号想象为正)

大于号返回-1,正乘负为负,所以降序

提示非常重要的一点,compareTo中的方法一定要有至少两个以上(其实两个足够)的返回值,而且一个返回值一定要小于0,另一个一定要大于或等于0。

否则排序不会成功。自己结合ComparableTimSort.class的countRunAndMakeAscending方法分析。

最后留一个问题:我们说可以按照年龄属性进行降序升序排序,但比如有如下要求。

要求按照年龄大小升序排列,当年龄相同时,按照name属性降序排列,这时候compareTo函数怎么写呢?

大家可以去思考一下,这里我就不贴代码出来了,相信大家看过前文,自己思考一下应该可以写出来。

好了,这个博客写了好多小时了,该结束了,现在是北京时间22:25。撤了,撤了,大家晚安。

2017/6/19/ 22:25 ---称心的毛巾

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。