不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2022-07-06 00:05:12  修改时间:2024-04-18 15:51:18  分类:Java基础  编辑

【重要】经验之谈:

在使用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
        */
    }
}

 

 

参考:

  1. https://www.zhanzhang365.com/archives/javacomparator的理解
  2. https://www.cnblogs.com/lemonu/p/13409446.html