java学习-Comparable compare(s1,s2)的比较原理


基本数据类型的包装类Integer, Float, Double,Long,Byte等都实现的Comparable接口,用于列表List或数组arrays的排序

Comparable<Integer>接口方法的实现,对象列表的升序降序接口

我们通过重写该接口方法,可以对列表进行升序或降序排列。

public int compareTo(T o);

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

此接口对实现它的每个类的对象强加一个默认排序。这种排序被称为类的自然排序,类的compareTo方法被称为其自然比较方法。

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort).  

实现的这个接口的对象list列表或array数组可以使用sort方法让列表或数组的元素被自动排序

 

要重写Compare方法需要满足下面的要求

比较其两个参数的顺序。当第一个参数小于,等于或大于第二个参数时,返回负整数,零或正整数。
在前面的描述中,符号sgn(expression)表示数学符号函数,该函数定义为根据表达式的值为负,零还是正返回-1、0或1中的一个。
实现者必须确保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x))。 (
这意味着,当且仅当compare(y,x)引发异常时,compare(x,y)才必须引发异常。)
实现者还必须确保该关系是可传递的:((compare(x,y)> 0 )&&(compare(y,z)> 0))意味着compare(x,z)> 0。
最后,实现者必须确保compare(x,y)== 0意味着所有z的sgn(compare(x,z))== sgn(compare(y,z))。
通常是这种情况,但并非严格要求(compare(x,y)== 0)==(x.equals(y))。
一般而言,任何违反此条件的比较器都应明确指出这一事实。推荐的语言是“注意:此比较器强加与等号不一致的顺序”。

上面的解释翻译过来是,

要满足 

int compare(T o1, T o2);

升序:o1>o2 返回1 并且 o1<o2 返回-1, o1==o2 返回0
降序:o1>o2  返回-1  并且 o1<o2 返回1, o1==o2 返回0
上面的条件必须满足要求才能按照设想的方式正确排序

例如

List<String> orderRule = new ArrayList<>(Arrays.asList("北京", "上海","广州"));
List<String> list = new ArrayList<>(Arrays.asList("天津","", "海南", "上海","广州","北京"));
 

//根据规则升序排序
countDtoList.sort(new Comparator<String>() {
   @Override
   public int compare(String dto1, String dto2){
      if (StringUtils.isBlank(dto2)) {
         //空名称放最后面
         return -1;
      }
      if (StringUtils.isBlank(dto1)) {
         //空名称放最后面
         return 1;
      }
      int i1 = orderRule.indexOf(dto1);
      int i2 = orderRule.indexOf(dto2);
      // 如果不在规则范围内的数据放到后面,则要保证
      // 如果1在,2不在,返回-1,如果1不在,2在,返回1。
      if (i2 < 0 && i1 >= 0) {
         return -1;
      }
      if (i1 < 0 && i2 >= 0) {
         return 1;
      }
      return i1 - i2;
   }
}

 

 

 

只需要实现compareTo()方法即可

public int compareTo(){}这个比较方法,,
如果要将对象列表进行升序排序,则第i个元素和第i+1元素 要满足a[i]>a[i+1] 返回1 a[i]<a[i+1] 返回-1 a[i]=a[i+1] 返回0

如果要将对象列表进行降序排序  要满足 a[i]>a[i+1] 返回-1 a[i]<a[i+1] 返回1 a[i]=a[i+1] 返回0
Collections.sort方法实现的就是按照此比较的东西排列
升序(从小到大):
if(price < o.price){
    return -1;
}
if(price > o.price){
   return 1;
}
降序(从大到小):
if(price < o.price){
   return 1;
}
if(price > o.price){
   return -1;
}
复制代码
    //将对象按价格进行升序排序
    @Override
    public int compareTo(flower o) {
        //首先比较price,如果price相同返回0
        if(price < o.price){
            return -1;
        }
        if(price > o.price){
            return 1;
        }
        
        return 0;
    }
复制代码

 

为什么升序  返回值为1时,是n的值要大于n+1的值,而返回值为-1时n的值要小于n+1呢?

这个要查看源码才可以知道原理。(不好奇的可以不看哦^~^)

 

由于这个List.sort()这个排序方法时使用二分排序,源码如下,

复制代码
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (pivot.compareTo(a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
复制代码

这个值是和已排序的数据的中间的数据进行比较,provot.compareTo(a[mid])

注意看,上面的a[mid]是作为比较方法的参数。

当小于0,也就是值为-1时,是我们要插入的数据作为调用方,

 

小于0时,该数据插入到前面,

大于0时,数据插入到后面

 

思维惯性以为升序就是第一个元素比第二个元素小。obj1.compareTo(Object obj2)

即obj1=2是第一个元素,obj2=8是第二个元素

那么我们升序时,如果obj1小于obj2,返回值为-1,则会将obj2插入到obj1前面,,排序前【2, 8】这样排序完后却变成了,,【8, 2】

这跟我们想要的升序数据不一样,

 

原因是java的二分法进行比较了是,,obj2.compareTo(obj1),,与我们想的刚好相反,

所以我们返回的值取反就可以变成升序了,

 

如这个消费类,,只给出部分代码

复制代码
public class ConsumInfo implements Comparable<ConsumInfo> {
    public double price;
   public String name;
  public Consuminfo(double price, String name){
   this.price = price;
   this.name = name;
  } @Override public int compareTo(ConsumInfo o) { //首先比较price,如果price相同 if(price < o.price){ return -1; } if(price > o.price){ return 1; } return 0; } }
复制代码
复制代码
    ConsumInfo consumInfo1 = new ConsumInfo("consumInfo1", 400.0);
       ConsumInfo consumInfo2 = new ConsumInfo("consumInfo2", 200.0);
    List<ConsumInfo> list = new ArrayList<ConsumInfo>(); list.add(consumInfo1); list.add(consumInfo2);     System.out.println("排序前:");     for(ConsumInfo consumInfo : list ){ System.out.println(consumInfo); }     Collections.sort(list);//排序     System.out.println("排序后:");//排序后 for(ConsumInfo consumInfo :list){ System.out.println(consumInfo); }
复制代码

控制台输出信息为:

排序前:
ConsumInfo [name=consumInfo1, price=400.0]
ConsumInfo [name=consumInfo2, price=200.0]
排序后:
ConsumInfo [name=consumInfo2, price=200.0]
ConsumInfo [name=consumInfo1, price=400.0]

上面是最简单的两个元素进行排序,

第一次,往已排序列表中插入第一个元素,即数组中只有一个已排好序的元素,a[0] = consumInfo1 

第二次时,left为0,right为1,进入while循环中,

mid=0,privot=consumInfo2

即consumInfo2.comparTo(a[0])

当方法的返回值小于0时,consumInfo2会插入在consumInfo1之前,

大于0时,会在consumInfo1之后

进行比较时,consumInfo2.price<consumInfo1.price    返回值小于0,也就是consumInfo1的值比较大,插入在1之前


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



猜您在找 8、将两个字符串s1,s2进行比较,如果s1>s2,则输出一个正数。如果s1 = s2,输出零。如果s1 < s2, 输出一个负数,不用strcmp函数,输出的正数或者负数的绝对值应该是比较两字符串相应字符的ascii码的差值。 为什么 String s1="hello" String s2 = new String("hello") s1==s2 为flase 编写一个程序,将连个字符串s1和s2比较,如果s1 > s2,输出一个整数;若s1 = s2,输出0;若s1 < s2,输出一个负数。不要用strcpy函数。两个字符串用gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相对应字符的ASCII码的差值。例如,"A"和“C”相比,由于"A" < "C",应输出负数,同时由于‘A’与‘C’的ASCII码差值为2,因此应输出"-2" 计算机S0、S1、S2、S3、S4、S5状态 ACPI电源管理中的S0 S1 S2 S3 S4 S5 计算机S0、S1、S2、S3、S4、S5状态 写一个函数,实现两个字符串的比较。即实现strcmp函数,s1=s2时返回0,s1!=s2时返回二者第一个不同字符的ASCII值。 编写一个程序,将两个字符串s1和s2比较,如果s1 > s2,输出一个整数;若s1 = s2,输出0;若s1 < s2,输出一个负数。不要用strcpy函数。两个字符串用gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相对应字符的ASCII码的差值。 使用java中汇编指令解析String对象(String s1="a";String s2=s1+"b";String s3=new String("a");String s4=s3+"a";) 电源选项中S1,S2,S3,S4,S5的含义
 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM