Java 中的自定义排序实现方法

Java 中的自定义排序实现方法

在Java中,排序是经常需要用到的操作,Java提供了两种通用的排序方法:

  • Arrays.sort()方法: 适用于基本类型数组和对象数组。
  • Collections.sort()方法: 适用于实现了Comparable接口的集合。

但是有时我们想自定义排序的规则,就要使用这两种方法的重载版本,传入自定义的比较器(Comparator)对象。

1. 使用自定义比较器对数组进行排序

1.1 实现Comparator接口

要自定义数组的排序规则,首先需要创建一个类,实现Comparator接口。该接口只有一个方法:

int compare(T o1, T o2);

该方法用于比较两个元素,并返回一个整数:

  • 如果o1小于o2,则返回-1。
  • 如果o1等于o2,则返回0。
  • 如果o1大于o2,则返回1。

例如,要按照字符串的长度对字符串数组进行排序,可以定义如下比较器:

class StringLengthComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
}

1.2 使用Arrays.sort()方法

有了自定义比较器之后,就可以使用Arrays.sort()方法对数组进行排序。该方法的重载版本接受一个数组和一个比较器对象作为参数:

Arrays.sort(array, comparator);

例如,要按照字符串的长度对字符串数组strArray进行排序,可以使用如下代码:

String[] strArray = {"abc", "12345", "abcdef"};
StringLengthComparator comparator = new StringLengthComparator();
Arrays.sort(strArray, comparator);

1.3 匿名内部类

如果只是为了简单的排序需求,可以使用匿名内部类来实现Comparator接口。例如,要按照字符串的自然顺序对字符串数组进行排序,可以使用如下代码:

Arrays.sort(strArray, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

1.4 代码结果


    class StringLengthComparator implements Comparator<String> {
        @Override
        public int compare(String s1, String s2) {
            return s1.length() - s2.length(); // to sort in ascending order
        }
    }

    public static void compareStrings2() {
        String[] strArray = { "12345", "abc", "abcdef" };
        StringLengthComparator comparator = new StringLengthComparator();
        Arrays.sort(strArray, comparator);
        System.out.println(Arrays.toString(strArray));
        // Output: [abc, 12345, abcdef]
        /*
         * 解释:`StringLengthComparator`类实现了`Comparator`接口
         * 并重写了`compare()`方法,以便根据字符串的长度进行比较。
         * `Arrays.sort()`方法用于根据
         * 自定义比较器对字符串数组进行排序。
     * https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343
         */

        Arrays.sort(strArray, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return -(s1.length() - s2.length());
            }
        });
        System.out.println(Arrays.toString(strArray));
        // Output: [abcdef, 12345, abc]
        /*
         * 解释:`Arrays.sort()`方法用于根据自定义比较器对字符串数组进行排序。
         * 在这种情况下,比较器是一个匿名类,它重写了`compare()`方法以便根据字符串的长度进行比较。
         * 返回负值,可以实现降序排序。
         */
    }

2. 使用自定义比较器对集合进行排序

2.1 实现Comparable接口

要自定义集合的排序规则,首先需要使集合中的元素类实现Comparable接口。该接口只有一个方法:

int compareTo(T o);

该方法用于比较当前对象和另一个对象的相对大小,并返回一个整数:

  • 如果当前对象小于另一个对象,则返回-1。
  • 如果当前对象等于另一个对象,则返回0。
  • 如果当前对象大于另一个对象,则返回1。

例如,要按照学生的分数对学生对象进行排序,可以定义如下学生类:

class Student implements Comparable<Student> {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public int compareTo(Student other) {
        return this.score - other.score;
    }
}

2.2 使用Collections.sort()方法

有了实现了Comparable接口的元素类之后,就可以使用Collections.sort()方法对集合进行排序。该方法的重载版本接受一个集合作为参数:

Collections.sort(collection);

例如,要按照学生的成绩对学生集合studentList进行排序,可以使用如下代码:

List<Student> studentList = new ArrayList<>();
studentList.add(new Student("Alice", 90));
studentList.add(new Student("Bob", 80));
studentList.add(new Student("Charlie", 70));
Collections.sort(studentList);

2.3 使用Lambda表达式

在Java 8及更高版本中,可以使用Lambda表达式来代替匿名内部类,使代码更加简洁。例如,要按照学生的成绩对学生集合studentList进行排序,可以使用如下代码:

studentList.sort((s1, s2) -> s1.getScore() - s2.getScore());

2.4 代码结果


    class Student implements Comparable<Student> {
        public String name;
        public int score;

        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }

        @Override
        public int compareTo(Student other) {
            return this.score - other.score;
        }
    }

    public static void compareObjects() {
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("Alice", 90));
        studentList.add(new Student("Bob", 80));
        studentList.add(new Student("Charlie", 70));
        Collections.sort(studentList);
        for (Student student : studentList) {
            System.out.println(student.name + ": " + student.score);
        }


        // Output:
        // Charlie: 70
        // Bob: 80
        // Alice: 90
        /*
         * 解释:`Student`类实现了`Comparable`接口并重写了`compareTo()`方法,
         * 以便根据学生的分数进行比较。`Collections.sort()`方法用于根据`compareTo()`方法定义的自然顺序对学生数组进行排序。
         * https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343
         */
    }

比较器的排序规则

在 Java 中,无论是实现 Comparable 接口的 compareTo 方法,还是创建 Comparator 接口的实例时实现的 compare 方法,其返回值都遵循一个通用的规则,以决定排序的顺序。

返回值规则

  • 负整数: 如果方法返回负整数,表示第一个参数(compareTo 中的 thiscompare 中的 o1)应该排在第二个参数(compareTo 中的 ocompare 中的 o2)之前。
  • 零: 如果方法返回零,表示这两个参数在排序时被视为相等。
  • 正整数: 如果方法返回正整数,表示第一个参数应该排在第二个参数之后。

举例

其实上文中的代码已经有过示例了,但是这里仍给出一个简单的示例并解释。

假设有一个 Person 类,其中包含 agename 两个字段,想要根据 agePerson 对象进行排序。

public class Person {
    int age;
    String name;

    // ...... https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343
}

Comparator<Person> byAge = new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.age - o2.age;
    }
};

在这个比较器中,如果 o1 的年龄小于 o2 的年龄,o1.age - o2.age 将返回一个负值,表示 o1 应该排在 o2 之前,从而实现了升序排序。
反之,如果 o1 的年龄大于 o2 的年龄,将返回一个正值,表示 o1 应该排在 o2 之后。
如果两者年龄相同,返回零,表示两者在排序时被视为相等。

注意点

  • 当实现 ComparatorComparable 时,返回值不必严格限制为-1、0 或 1。任何负整数值都表示“小于”,任何正整数值都表示“大于”。
  • 在实现比较逻辑时,特别是涉及到数值差异计算的场景(如上述例子中的 o1.age - o2.age),要注意数值溢出的问题。对于大整数的比较,推荐使用 Integer.compare(x, y)Long.compare(x, y) 等静态方法,这些方法内部已经处理了溢出问题。

比较两个接口

ComparableComparator 都是 Java 中用来实现对象排序的接口,它们在用法和设计目的上有一些关键的不同之处:

Comparable 接口

  • 包路径: java.lang.Comparable
  • 用途: 当我们想要定义一个类的自然排序时使用。例如,一个 Person 类可能按照年龄或姓名自然排序。
  • 方法: 该接口只包含一个方法 compareTo(T o),任何实现了 Comparable 接口的类都必须实现这个方法。
  • 实现方式: 类内部比较机制,即一个对象自己知道如何与另一个对象进行比较。
  • 使用场景: 适用于你拥有源代码的类,并且你希望该类的对象有一个默认的排序方式。

Comparator 接口

  • 包路径: java.util.Comparator
  • 用途: 当我们需要定义多种排序方式,或者我们无法修改要排序的类的源代码时使用。例如,如果 Person 类是一个第三方库的一部分,我们无法为其实现 Comparable 接口,但我们仍然想要根据年龄或姓名对 Person 对象进行排序。
  • 方法: 该接口包含一个方法 compare(T o1, T o2),用于比较两个对象。
  • 实现方式: 类外部比较机制,即我们创建一个单独的比较器(Comparator)来定义两个对象如何比较。
  • 使用场景: 当你需要对某个类的对象进行排序,但是你不能修改原始类,或者你需要对同一个类的对象以不同的方式进行排序时。

总结

  • 修改源代码: 如果可以修改类的源代码,并且该类有一个自然的排序顺序,使用 Comparable
  • 多种排序方式或无法修改源代码: 如果你需要多种排序方式,或者你无法修改要排序的类,使用 Comparator

使用 ComparableComparator 可以让你的对象支持排序操作,如使用 Collections.sort()Arrays.sort() 方法进行排序。选择哪一个取决于你的具体需求和上述提到的考量。

比较两个方法

Arrays.sort()Collections.sort() 都是 Java 中用于排序的常用方法,但它们之间存在一些关键的区别,主要体现在它们的使用场景和内部工作机制上。

Arrays.Sort ()

  • 定义位置: java.util.Arrays 类中。
  • 使用场景: 用于对数组进行排序。可以对原始数据类型数组(如 int[], double[] 等)和对象数组(如 String[], Integer[] 等)进行排序。
  • 工作原理: Arrays.sort() 方法根据数组的数据类型采用不同的排序算法。对于原始数据类型数组,通常采用快速排序算法;而对于对象数组,则使用改进的归并排序(TimSort)。
  • 重载版本: 提供了多个重载方法,允许你对整个数组或指定范围内的元素进行排序。也可以接受一个 Comparator,用于对象数组的定制排序。

Collections.Sort ()

  • 定义位置: java.util.Collections 类中。
  • 使用场景: 专门用于对实现了 List 接口的集合进行排序,比如 ArrayList, LinkedList 等。
  • 工作原理: Collections.sort() 内部也是使用改进的归并排序算法(TimSort)来对列表进行排序。
  • 重载版本: 提供了两种形式的 sort 方法。一种是只接受 List 对象,按照元素的自然顺序进行排序;另一种是除了 List 对象外,还接受一个 Comparator 参数,用于定制排序规则。

关键区别

  • 应用类型: Arrays.sort() 用于数组,而 Collections.sort() 用于 List 接口的集合。
  • 排序算法: 对于原始类型数组,Arrays.sort() 可能使用快速排序;对于对象类型数组和 Collections.sort(),则使用 TimSort 算法。
  • 灵活性: Collections.sort() 只能用于 List 集合,而 Arrays.sort() 可以对任何类型的数组进行排序,包括原始数据类型和对象数组。
  • 定制排序: 两者都支持定制排序,允许通过传递 Comparator 实现特定的排序逻辑。

在选择使用 Arrays.sort() 还是 Collections.sort() 时,主要考虑要排序的数据类型(数组还是 List 集合)。对于集合框架中的列表,推荐使用 Collections.sort()。对于数组类型的数据,则必须使用 Arrays.sort()

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java实现自定义排序可以使用Comparator接口。Comparator接口有一个compare()方法,通过实现这个方法可以定义自己的排序规则。在使用Arrays.sort()方法或List的sort()方法时,可以传入Comparator对象来实现自定义排序。 例如,在一个乱序的整数数组,如果想要按照从小到大的顺序进行排序,可以实现一个Comparator<Integer>对象,并在compare()方法定义排序规则。比如,可以使用o1 - o2来表示按照升序排序。然后将这个Comparator对象传入Arrays.sort()方法,即可实现自定义排序。 具体代码示例如下: ```java public class Solution { public String sort(Integer[] nums) { Arrays.sort(nums, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // 从小到大的顺序排序 return o1 - o2; } }); return Arrays.toString(nums); } } public class Main { public static void main(String[] args) { Solution solution = new Solution(); Integer[] arr = {5, 1, 3, 2, 4}; System.out.println(solution.sort(arr)); } } ``` 这段代码,我们创建了一个Solution类,其的sort()方法接收一个整数数组作为参数。在sort()方法,我们使用Arrays.sort()方法来对数组进行排序,并传入一个实现了Comparator<Integer>接口的匿名内部类对象。在匿名内部类的compare()方法,我们定义了按照从小到大的顺序排序的规则。 在main()方法,我们创建了一个Main类的对象,并调用sort()方法进行排序,并将排序后的结果打印出来。 这样就实现了对一个乱序数组进行升序排序自定义排序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值