美文网首页
Comparable和Comparator比较器及其在排序中的应

Comparable和Comparator比较器及其在排序中的应

作者: topshi | 来源:发表于2019-04-25 11:40 被阅读0次

前言

昨天做题时用到了比较器实现排序,例如用Arrays.sort()对一个整型数组nums排序,是升序排序的,因为Integer类实现的Comparable接口是这样的,

    public static int compare(int var0, int var1) {
        return var0 < var1 ? -1 : (var0 == var1 ? 0 : 1);
    }

如果想实现降序排序,可以给Arrays.sort()方法传递一个Comparator比较器。

Arrays.sort(nums,new Comparator(){
                  public int compare(Integer t1, Integer t2){
                          return t2 - t1;
                  }});

那么问题来了,为什么return t2 - t1就是降序了呢?本文来学习下Comparable和Comparator比较器。
需要为多个对象排序时必须设置排序规则,而排序规则可以通过比较器进行设置,java提供了两种比较器:Comparable和Comparator。

Comparable接口

Comparable是一个要进行多个对象比较的类需要默认实现的接口,定义如下:

public interface Comparable<T> {
    int compareTo(T var1);
}

compareTo()方法返回一个int类型的结果,该返回值分三种情况,负值、0和正值,分别用-1,0,1表示:

  • 相等 -> 0
  • 大于 -> 1
  • 小于 -> -1

Comparable示例

/**
 * @Time : 2019/04/25 上午 10:26
 * @Author : xiuc_shi
 **/
public class Book implements Comparable<Book>{
    private String name;
    private double price;
    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
    @Override
   //按价格升序排序
    public int compareTo(Book o) {
        return this.price < o.price ? -1 : (this.price == o.price ? 0 : 1);
    }
}

Test.java

import java.util.Arrays;
/**
 * @Time : 2019/04/25 上午 10:29
 * @Author : xiuc_shi
 **/
public class Test {
    public static void main(String[] args) {
        Book[] books = new Book[4];
        books[0] = new Book("java开发实战",85.3);
        books[1] = new Book("java并发编程",75.3);
        books[2] = new Book("java入门到精通",78.5);
        books[3] = new Book("算法",75.8);
        Arrays.sort(books);
        for(Book book : books){
            System.out.println(book);
        }
    }
}
>结果
Book{name='java并发编程', price=75.3}
Book{name='算法', price=75.8}
Book{name='java入门到精通', price=78.5}
Book{name='java开发实战', price=85.3}

如果要实现价格降序排序只需要修改compare()方法:

  //按价格降序排序
    public int compareTo(Book o) {
        return o.price < this.price ? -1 : (this.price == o.price ? 0 : 1);
    }

挽救比较规则的比较器:Comparator

从上面的例子可以Book实体类实现了Comparable接口,从而确定了Book的比较规则,可以说Comparable是内联到Book类中的,调用compareTo()方法需要使用到Book的实例。
问题是:如果Book没有实现Comparable接口,而又不能对Book类进行修改了,那么应该如何给Book类设置比较规则呢?这可以通过Comparator接口来挽救。
Comparator接口部分定义:

public interface Comparator<T> {
    int compare(T var1, T var2);
    boolean equals(Object var1);

compare()方法实现了比较规则,var1和var2是比较的两个对象,返回结果分三种情况,负值、0和正值,分别用-1,0,1表示:

  • var1 == var2 -> 0
  • var1 < var2 -> -1
  • var1 > var2 -> 1

Comparator示例

/**
 * @Time : 2019/04/25 上午 10:26
 * @Author : xiuc_shi
 **/
public class Book{
    private String name;
    private double price;
    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

BookComparator类实现Comparator接口,给Book类提供比较规则。

import java.util.Comparator;
/**
 * @Time : 2019/04/25 上午 10:55
 * @Author : xiuc_shi
 **/
public class BookComparator implements Comparator<Book> {
    @Override
    //按价格降序排序
    public int compare(Book book, Book t1) {
        return t1.getPrice() < book.getPrice() ? -1 : 
                              (book.getPrice() == t1.getPrice() ? 0:1);
    }
}

Test.java

import java.util.Arrays;
import java.util.Comparator;

/**
 * @Time : 2019/04/25 上午 10:29
 * @Author : xiuc_shi
 **/
public class Test {
    public static void main(String[] args) {
        Book[] books = new Book[4];
        books[0] = new Book("java开发实战",85.3);
        books[1] = new Book("java并发编程",75.3);
        books[2] = new Book("java入门到精通",78.5);
        books[3] = new Book("算法",75.8);
        //给Arrays.sort传递比较规则
        Arrays.sort(books,new BookComparator());
        for(Book book : books){
            System.out.println(book);
        }
    }
}
> 结果
Book{name='java开发实战', price=85.3}
Book{name='java入门到精通', price=78.5}
Book{name='算法', price=75.8}
Book{name='java并发编程', price=75.3}

比较器升降序排序原理

首先粗略看下Arrays.sort()的源码,

private static void mergeSort(Object[] var0, Object[] var1, int var2, int var3, int var4, Comparator var5) {
        int var6 = var3 - var2;
        int var7;
        int var8;
        if (var6 < 7) {
            for(var7 = var2; var7 < var3; ++var7) {
                for(var8 = var7; var8 > var2 && var5.compare(var1[var8 - 1], var1[var8]) > 0; --var8) {
                    swap(var1, var8, var8 - 1);
                }
            }

var1[var8] 和 var1[var8 - 1] 比较,满足var5.compare(var1[var8 - 1], var1[var8]) > 0这个条件,var1[var8] 和 var1[var8 - 1] 交换位置。
被往前移的var1[8]到底是var1[8] > var1[var8 - 1]还是var1[8] < var1[var8 - 1],取决于我们的比较规则。

  • 若compare()实现为
 public int compare(Integer t1, Integer t2){
        return t2 - t1;
 }

var5.compare(var1[var8 - 1], var1[var8]) > 0条件满足时,显然是t2 > t1t2将被向前移,这就是降序排序。

  • 若compare()实现为
 public int compare(Integer t1, Integer t2){
        return t1 - t2;
 }

var5.compare(var1[var8 - 1], var1[var8]) > 0条件满足时,显然是t1 > t2t2将被向前移,这就是升序排序。

总结

  • 我们在写升序降序的比较规则时,只需要记住compare()方法返回值大于0时,后一个参数会被前移,那么在设计排序规则时就容易了。
//t1 > t2, t2前移
public int compare(Integer t1, Integer t2){
      return t1 - t2;
}
  • 实现Comparable接口的类在调用Arrays.sort(Object[] var0)方法时默认使用类的compareTo()方法的比较规则,所以int型和double型的数组在排序时是升序排序的。
private static void mergeSort(Object[] var0, Object[] var1, int var2, int var3, int var4) {
        int var5 = var3 - var2;
        int var6;
        int var7;
        if (var5 < 7) {
            for(var6 = var2; var6 < var3; ++var6) {
                for(var7 = var6; var7 > var2 && ((Comparable)var1[var7 - 1]).compareTo(var1[var7]) > 0; --var7) {
                    swap(var1, var7, var7 - 1);
                }
            }

相关文章

网友评论

      本文标题:Comparable和Comparator比较器及其在排序中的应

      本文链接:https://www.haomeiwen.com/subject/vaxagqtx.html