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

文章目录

  • Java 中的自定义排序实现方法
    • 1. 使用自定义比较器对数组进行排序
      • 1.1 实现`Comparator`接口
      • 1.2 使用`Arrays.sort()`方法
      • 1.3 匿名内部类
      • 1.4 代码结果
    • 2. 使用自定义比较器对集合进行排序
      • 2.1 实现`Comparable`接口
      • 2.2 使用`Collections.sort()`方法
      • 2.3 使用Lambda表达式
      • 2.4 代码结果
    • 比较器的排序规则
      • 返回值规则
      • 举例
      • 注意点
    • 比较两个接口
      • `Comparable` 接口
      • `Comparator` 接口
      • 总结
    • 比较两个方法
      • Arrays.Sort ()
      • Collections.Sort ()
      • 关键区别

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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/589212.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何快速的追加文章的内容(在不知道内容的情况下)

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 1、打开工具&#xff0c;切换到文章模块下&#xff0c;快捷键&#xff1a;Ctrl1 2、新建一个文章做演示&#xff0c;001 3、添加一个内容&#xff0c;就随…

蚂蚁面试:Springcloud核心组件的底层原理,你知道多少?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格&#xff0c;遇到很多很重要的相关面试题&#xff1a; 说说&#xff1a;蚂蚁面试&#xff1…

【Java】HOT100 贪心算法

目录 理论基础 一、简单贪心 LeetCode455&#xff1a;分发饼干 二、中等贪心 2.1 序列问题 LeetCode376&#xff1a;摆动序列 2.2 贪心股票问题 LeetCode121&#xff1a;买卖股票的最佳时机 LeetCode121&#xff1a;买卖股票的最佳时机ii 2.3 两个维度权衡问题 LeetCode135&…

【06016传感器原理与应用】第5章 气敏传感器 期末复习自考复习

第5章 气敏传感器 能够把气体信息变成电信号的装置。 一、学习目的与要求 通过本章的学习&#xff0c;熟悉并掌握气体传感器的工作原理和硬件组成结构。熟练掌握几种电阻式尤其TiO2、SnO2气敏传感器、非电阻式气敏传感器、固体电解质传感器、接触燃烧式气敏传感器的基本原理…

karpathy makemore 3

1 Introduction 这一章&#xff0c;karpathy通过分析参数初始化对模型的收敛的影响作为一个引子&#xff0c;让我们看到神经网络这一个复杂的系统&#xff0c;对grad非常敏感&#xff0c;以及有一些技巧可以解决grad敏感的问题。 2 准备工作 2.1 dataloader import torch b…

DS:顺序表、单链表的相关OJ题训练

欢迎各位来到 Harper.Lee 的学习小世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu可以来后台找我交流哦&#xff01; 在DS&#xff1a;单链表的实现 和 DS&#xff1a;顺序表的实现这两篇文章中&#xff0c;我详细介绍了顺序表和单链表的…

PAT (Advanced Level) - 1047 Student List for Course

模拟 #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std;const int N 40010, M 2510;int n, k; string name[N]; vector<int> list[M];int main() {scanf("%d%d", &n, &…

万万没想到,延缓帕金森病进展的“玄机”竟然就在腿上?【北京仁爱堂】

帕金森病患者的腿部变化&#xff0c;其实可以反应出很多问题。例如行走的变化问题、步态的异常等问题&#xff0c;可以反应病情轻重程度。而通过保持腿部肌肉活动的状态&#xff0c;也可以使帕金森病的症状得到一定的缓解&#xff0c;甚至有助于防止病情恶化。 帕金森病腿部变…

2024年五一数学建模竞赛C题论文首发

基于随机森林的煤矿深部开采冲击地压危险预测 摘要 煤炭作为中国重要的能源和工业原料&#xff0c;其开采活动对国家经济的稳定与发展起着至关重要的作用。本文将使用题目给出的数据探索更为高效的数据分析方法和更先进的监测设备&#xff0c;以提高预警系统的准确性和可靠性…

Photoshop前言

Photoshop前言 分辨率图像格式工具界面组件 分辨率 分辨率是指单位长度内包含的像素点的数量&#xff0c;其单位通常为像素/英寸&#xff08;ppi&#xff09;&#xff0c;300ppi表示每英寸包含300个像素点。对于1英寸1英寸大小的图像&#xff0c;若分辨率为72ppi&#xff0c;则…

基于Pytorch深度学习——多层感知机

本文章来源于对李沐动手深度学习代码以及原理的理解&#xff0c;并且由于李沐老师的代码能力很强&#xff0c;以及视频中讲解代码的部分较少&#xff0c;所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉&#xff0c;所以我们会采用逐行解释小…

Visio 2021 (64bit)安装教程

Visio 2021 (64bit)安装教程 ​ 通知公告 Visio 2021 (64位) 是一款流程图和图表设计工具,主要用于创建和编辑各种类型的图表和图形。它提供了一个直观的界面和丰富的功能,可以帮助用户快速绘制专业的流程图、组织结构图、网络图、平面图、数据库模型等。 具体来说,Visio 20…

Go 语言数组

Go 语言提供了数组类型的数据结构。 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列&#xff0c;这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。 相对于去声明 number0, number1, ..., number99 的变量&#xff0c;使用数组形式 numbers[0], num…

Spring Cloud——Circuit Breaker上篇

Spring Cloud——Circuit Breaker上篇 一、分布式系统面临的问题1.服务雪崩2.禁止服务雪崩故障 二、Circuit Breaker三、resilience4j——服务熔断和降级1.理论知识2.常用配置3.案例实战&#xff08;1&#xff09;COUNT_BASED&#xff08;计数的滑动窗口&#xff09;&#xff0…

Spring Cloud——OpenFeign

Spring Cloud——OpenFeign 一、OpenFeign能干嘛二、OpenFeign的基本使用三、Feign的高级特性1.OpenFeign超时控制2.OpenFeign重试机制3.OpenFeign之性能优化HttpClient54.OpenFeign请求和响应压缩5.OpenFeign之Feign日志打印 四、参考 OpenFeign是一个声明式的Web服务客户端。…

Android --- 消息机制与异步任务

在Android中&#xff0c;只有在UIThread(主线程)中才能直接更新界面&#xff0c; 在Android中&#xff0c;长时间的工作联网都需要在workThread(分线程)中执行 在分线程中获取服务器数据后&#xff0c;需要立即到主线程中去更新UI来显示数据&#xff0c; 所以&#xff0c;如…

程序员的五大方法论

前言&#xff1a; 最近看了一篇总结程序员学习&#xff0c;晋升方法的文章&#xff0c;颇有感想&#xff0c;决定分享给大家&#xff0c;原文地址&#xff1a;给程序员的5条学习方法论 (qq.com)https://mp.weixin.qq.com/s/xVFlF9qTf9c74Emmdm0DqA 在繁忙的工作中&#xff0c;持…

如何在postman上提交文件格式的数据

如何在postman上提交文件格式的数据 今天在写一个文件上传的功能接口时&#xff0c;想用postman进行提交&#xff0c;花了些时间才找到在postman提交文件格式的数据。记录一下吧&#xff01; 1.打开postman&#xff0c;选择POST提交方式&#xff0c;然后在Params那一行的Head…

代码随想录算法训练营DAY45|C++动态规划Part7|70.爬楼梯(进阶版)、322. 零钱兑换、279.完全平方数

文章目录 70.爬楼梯&#xff08;进阶版&#xff09;322. 零钱兑换思路CPP代码 279.完全平方数思路CPP代码 70.爬楼梯&#xff08;进阶版&#xff09; 卡码网&#xff1a;57. 爬楼梯 文章讲解&#xff1a;70.爬楼梯(进阶版) 322. 零钱兑换 力扣题目链接 文章讲解&#xff1a;322…

安装英伟达nvidia p4计算卡驱动@FreeBSD14

FreeBSD也能跑cuda AI训练拉&#xff01; 在FreeBSD安装好pytorch和飞桨cpu版本后&#xff0c;尝试安装英伟达nvidia p4计算卡驱动。毕竟全靠cpu速度太慢了&#xff0c;还是GPU快啊&#xff01;在磕磕绊绊几天后&#xff0c;终于成功成功安装好nvidia p4的cuda驱动&#xff0c…
最新文章