前言
昨天做题时用到了比较器实现排序,例如用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 > t1
,t2
将被向前移,这就是降序排序。
- 若compare()实现为
public int compare(Integer t1, Integer t2){
return t1 - t2;
}
var5.compare(var1[var8 - 1], var1[var8]) > 0
条件满足时,显然是t1 > t2
,t2
将被向前移,这就是升序排序。
总结
- 我们在写升序降序的比较规则时,只需要记住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);
}
}
网友评论