【重要】经验之谈:
在使用Java自带的排序函数时,往往需要根据自己的需求,自定义比较器。那么问题来了,比较器是怎么确定按“升序”排序还是“降序”排序的呢?
实现Comparaotor接口,必须实现下面这个函数:
@Override
public int compare(CommentVo v1, CommentVo v2) {
return v1-v2; //升序
return v2-v1; //降序
}
其实,是根据返回值判断的,如果返回值为1(即>0),则交换v1、v2的位置,否则不换。
例如:
v1=5, v2=6;
- return v1-v2; 5-6 返回值为-1 (<0),不交换,顺序为v1、v2,结果为升序。
- return v2-v1; 6-5 返回值为1 (>0),交换,交换后顺序为:v2、v1,结果为降序。
Java排序器之升序or降序
一、如何确定升序还是降序?
Java中在进行对象排序时,设计的排序器经常会对两个对象按照一定的排序规则排序,可如何确定排序规则是升序还是降序呢?笔者整理了一个简单的方法来确定排序规则。
o1和o2是需要表示排序的两个对象,假定比较前的默认顺序为 [o1, o2],是升序还是降序暂时不做考虑,完全根据返回值结果表示是否需要调整当前的排序顺序,便能够理解排序的真正逻辑,以确定是升序排序还是降序排序。
假设我们的比较器规则如下:o1对象作为比较的前者,o2对象作为排序的后者,即比较方式为 [o1 - o2]或者 [o1.compareTo(o2)]。
class ComparatorByAge implements Comparator {
// 根据年龄和姓名排序
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int tmp = p1.getAge() - p2.getAge();
return tmp == 0 ? p1.getName().compareTo(p2.getName()) : tmp;
}
}
升序规则:
- o1 > o2,返回正数,true,表示需要调整顺序,升序。
- o1 < o2,返回负数,false,表示不需要调整顺序,升序。
降序规则:
- o1 > o2,返回负数,false,表示不需要调整顺序,降序。
- o1 < o2,返回正数,true,表示需要调整顺序,降序。
不排序规则:
- o1 = o2,返回0,按当前顺序即可,或者比较其他参数。
二、实际用例
Person 是定义的需要排序的对象,包括年龄和姓名两个字段。
class Person implements Comparable{
private String name;
private int age;
// 重写toString()方法,输出对象时输出格式为:name:age
@Override
public String toString() {
return name+ ":" + age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
// Person自带的排序规则
@Override
public int compareTo(Object o) {
Person p = (Person) o;
// 根据年龄进行排序
int temp = this.age - p.age;
return temp == 0 ? this.name.compareTo(p.name):temp;
}
}
排序规则一:定义升序排序器,先按年龄升序,再按姓名首字母升序。
- 比如 o1对象为 (zhangshan:20) ,o2 对象为 (wangwu:21) ,默认排序 [o1, o2],由于 o1.age < o2.age,比较结果返回负数,false,表示不需要调整规则,按年龄升序排序,最终排序结果为 [zhangshan:20, wangwu:21]。
- 比如 o1 对象为 (zhangshan:20) ,o2对象为 (lisi:20),默认排序 [o1,o2],由于 o1.age = o2.age,比较结果为0,不按年龄排序,进一步比较name,由于 o1.name > o2.name,返回 true,调整排序规则,即按字母升序排序,最终排序结果为 [lisi:20, zhangshan:20]。
/**
* 自定义升序排序器
* 升序:先按年龄升序,再按姓名首字母升序
*/
class ComparatorByAge implements Comparator {
// 根据年龄排序
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int tmp = p1.getAge() - p2.getAge();
return tmp == 0 ? p1.getName().compareTo(p2.getName()) : tmp;
}
}
排序规则二:定义降序排序器,先按年龄降序,再按姓名首字母降序。和升序的唯一区别就是返回结果的参数前添加了一个负号。
/**
* 自定义降序排序器
* 降序:先按年龄降序,再按姓名首字母降序
*/
class ComparatorByAge2 implements Comparator {
// 根据年龄排序
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int tmp = p1.getAge() - p2.getAge();
return tmp == 0 ? -(p1.getName().compareTo(p2.getName())) : -tmp;
}
}
排序 main() 方法,查看两种排序器的排序结果。
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Person> ts = new TreeSet(new ComparatorByAge());
ts.add(new Person("zhangsan", 20));
ts.add(new Person("wangwu", 21));
ts.add(new Person("lisi", 20));
ts.add(new Person("zhouqi", 29));
ts.add(new Person("zhaoliu", 28));
for (Person person : ts) {
System.out.println(person);
}
/* 结果输出
lisi:20
zhangsan:20
wangwu:21
zhaoliu:28
zhouqi:29
*/
ts = new TreeSet(new ComparatorByAge2());
ts.add(new Person("zhangsan", 20));
ts.add(new Person("wangwu", 21));
ts.add(new Person("lisi", 20));
ts.add(new Person("zhouqi", 29));
ts.add(new Person("zhaoliu", 28));
for (Person person : ts) {
System.out.println(person);
}
/* 结果输出
zhouqi:29
zhaoliu:28
wangwu:21
zhangsan:20
lisi:20
*/
}
}
参考: