Java中Comparator排序原理详解
引言
在Java编程中,集合排序是一个常见需求。很多开发者对于为什么o2-o1
实现降序排列而o1-o2
实现升序排列感到困惑。本文将从数学角度解析这个问题,帮助读者彻底理解Comparator的排序原理。
问题引入
看看以下排序代码:
List<Student> students = new ArrayList<>();
students.add(new Student("张三", 85));
students.add(new Student("李四", 92));
students.add(new Student("王五", 78));
students.add(new Student("赵六", 96));// 按成绩排序
Collections.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o2.getScore() - o1.getScore(); // 降序排列}
});
为什么使用o2.getScore() - o1.getScore()
会使学生按成绩降序排列,而使用o1.getScore() - o2.getScore()
则会使其按成绩升序排列呢?
Comparator接口基础
在Java中,Comparator
接口的compare
方法返回一个整数值,这个值遵循以下约定:
- 返回负数:表示第一个参数应该排在第二个参数前面
- 返回正数:表示第一个参数应该排在第二个参数后面
- 返回零:表示两个参数相等,顺序无关紧要
这个约定是理解排序机制的基础。
数学角度分析
为了更清晰地分析这个问题,我们用a和b代替o1和o2。
升序排列:a-b
当我们使用a-b
作为比较逻辑时:
-
当a < b时:
- 计算结果:a-b < 0(负数)
- 根据Comparator约定:a应排在b前面
- 排序效果:较小的值在前,较大的值在后
- 结论:升序排列
-
当a > b时:
- 计算结果:a-b > 0(正数)
- 根据Comparator约定:a应排在b后面
- 排序效果:较大的值在后,较小的值在前
- 结论:升序排列
降序排列:b-a
当我们使用b-a
作为比较逻辑时:
-
当a < b时:
- 计算结果:b-a > 0(正数)
- 根据Comparator约定:a应排在b后面
- 排序效果:较小的值在后,较大的值在前
- 结论:降序排列
-
当a > b时:
- 计算结果:b-a < 0(负数)
- 根据Comparator约定:a应排在b前面
- 排序效果:较大的值在前,较小的值在后
- 结论:降序排列
数学等价关系
从数学角度看,b-a
实际上等价于-(a-b)
:
当a-b < 0时,-(a-b) > 0
当a-b > 0时,-(a-b) < 0
这种数学等价关系导致了排序结果的完全反转:
- 如果
a-b
产生升序排列 - 那么
-(a-b)
或b-a
将产生降序排列
实际例子
以学生成绩排序为例,假设有两个成绩:90分和85分
使用a-b(升序):
- compare(90, 85) = 90-85 = 5(正数)
- 根据约定,90应排在85后面
- 结果:[85, 90],分数从低到高排列
使用b-a(降序):
- compare(90, 85) = 85-90 = -5(负数)
- 根据约定,90应排在85前面
- 结果:[90, 85],分数从高到低排列
这个例子直观地展示了为什么a-b
产生升序,而b-a
产生降序。
代码应用示例
List<Integer> scores = Arrays.asList(78, 92, 85, 96, 70);// 升序排列
Collections.sort(scores, (a, b) -> a - b);
// 结果:[70, 78, 85, 92, 96]// 降序排列
Collections.sort(scores, (a, b) -> b - a);
// 结果:[96, 92, 85, 78, 70]
使用Lambda表达式可以更简洁地实现排序,原理完全相同。
总结
a-b
和b-a
的排序结果差异,不是巧合,而是基于以下两点的必然结果:
- 减法运算的数学特性:数值大小与结果正负的关系
- Comparator接口的设计约定:返回值正负与排序顺序的关系
理解了这一原理,我们就能根据需要轻松实现升序或降序排列。
注意事项
在实际应用中需要注意:
-
防止整数溢出:当处理极大或极小的整数时,简单的减法可能导致溢出
// 不安全的写法(可能溢出) return a - b;// 安全的写法 return Integer.compare(a, b);
-
浮点数比较:浮点数应使用Double.compare()方法而非直接相减
// 推荐写法 return Double.compare(a, b); // 升序 return Double.compare(b, a); // 降序
掌握了Comparator的核心原理,我们就能在各种场景中灵活应用,实现各种复杂的排序需求。
相关文章:
Java中Comparator排序原理详解
引言 在Java编程中,集合排序是一个常见需求。很多开发者对于为什么o2-o1实现降序排列而o1-o2实现升序排列感到困惑。本文将从数学角度解析这个问题,帮助读者彻底理解Comparator的排序原理。 问题引入 看看以下排序代码: List<Student&…...
PyQt5基础:QWidget类的全面解析与应用实践
在Python的GUI编程领域,PyQt5是一个强大且广泛应用的库。其中,QWidget类作为所有用户界面对象的基类,是构建丰富多样用户界面的基础。今天,我们就来深入了解QWidget类及其相关应用。 QWidget类概述 QWidget类是PyQt中所有窗口和…...
Python-77:古生物DNA序列血缘分析
问题描述 小U是一位古生物学家,正在研究不同物种之间的血缘关系。为了分析两种古生物的血缘远近,她需要比较它们的DNA序列。DNA由四种核苷酸A、C、G、T组成,并且可能通过三种方式发生变异:添加一个核苷酸、删除一个核苷酸或替换一…...

QT6 源(82):阅读与注释日历类型 QCalendar,本类并未完结,儒略历,格里高利历原来就是公历,
(1)本代码来自于头文件 qcalendar . h : #ifndef QCALENDAR_H #define QCALENDAR_H#include <limits>#include <QtCore/qglobal.h> #include <QtCore/qlocale.h> #include <QtCore/qstring.h> #include <QtCore/…...

CVE体系若消亡将如何影响网络安全防御格局
CVE体系的核心价值与当前危机 由MITRE运营的通用漏洞披露(CVE)项目的重要性不容低估。25年来,它始终是网络安全专业人员理解和缓解安全漏洞的基准参照系。通过提供标准化的漏洞命名与分类方法,这套体系为防御者建立了理解、优先级…...

OpenKylin安装Elastic Search8
一、环境准备 Java安装 安装过程此处不做赘述,使用以下命令检查是否安装成功。 java -version 注意:Elasticsearch 自 7.0 版本起内置了 OpenJDK,无需单独安装。但如需自定义 JDK,可设置 JAVA_HOME。 二、安装Elasticsearch …...

【ARM AMBA AHB 入门 3 -- AHB 总线介绍】
请阅读【ARM AMBA 总线 文章专栏导读】 文章目录 AHB Bus 简介AHB Bus 构成AHB BUS 工作机制AHB 传输阶段 AHB InterfacesAHB仲裁信号 AHB 数据访问零等待传输(no waitstatetransfer)等待传输(transfers with wait states)多重传送(multipletransfer)--Pipeline AHB 控制信号 A…...

多模态大模型中的视觉分词器(Tokenizer)前沿研究介绍
文章目录 引言MAETok背景方法介绍高斯混合模型(GMM)分析模型架构 实验分析总结 FlexTok背景方法介绍模型架构 实验分析总结 Emu3背景方法介绍模型架构训练细节 实验分析总结 InternVL2.5背景方法介绍模型架构 实验分析总结 LLAVA-MINI背景方法介绍出发点…...

sqli-labs靶场第二关——数字型
一:查找注入类型: 输入 ?id1--与第一关的差别:报错; 说明不是字符型 渐进测试:?id1--,结果正常,说明是数字型 二:判断列数和回显位 ?id1 order by 3-- 正常, 说明有三列&am…...
使用FastAPI微服务在AWS EKS上实现AI会话历史的管理
架构概述 本文介绍如何使用FastAPI构建微服务架构,在AWS EKS上部署两个微服务: 服务A:接收用户提示服务B:处理对话逻辑,与Redis缓存和MongoDB数据库交互 该架构利用AWS ElastiCache(Redis)实现快速响应,…...

[模型选择与调优]机器学习-part4
七 模型选择与调优 1 交叉验证 (1) 保留交叉验证HoldOut HoldOut Cross-validation(Train-Test Split) 在这种交叉验证技术中,整个数据集被随机地划分为训练集和验证集。根据经验法则,整个数据集的近70%被用作训练集ÿ…...

【计算机网络-数据链路层】以太网、MAC地址、MTU与ARP协议
📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🅒 C 语言 | 🌐 计算机网络 上篇文章:传输层-TCP协议TCP核心机制与可靠性保障 下篇文章: 网络…...
学习适应对智能软件对对象的属性进行表征、计算的影响
下面的链接是我新发表的文章。这篇文章是关于智能软件对对象进行标志、表征的问题,这是所有智能实体都无法回避的基本问题。 我最近写了一篇关于奖惩系统的文章。并开始写智能是如何在基础编程的基础上涌现出来的文章。 https://www.oalib.com/articles/6857382 …...
vue 组件函数式调用实战:以身份验证弹窗为例
通常我们在 Vue 中使用组件,是像这样在模板中写标签: <MyComponent :prop"value" event"handleEvent" />而函数式调用,则是让我们像调用一个普通 JavaScript 函数一样来使用这个组件,例如:…...
多线程面试题总结
基础概念 进程与线程的区别 进程:操作系统资源分配的基本单位,有独立内存空间线程:CPU调度的基本单位,共享进程资源对比: 创建开销:进程 > 线程通信方式:进程(IPC)、线程(共享内存)安全性:进程更安全(隔离),线程需要同步线程的生命周期与状态转换 NEW → RUNNABLE …...

Kafka 与 RabbitMQ、RocketMQ 有何不同?
一、不同的诞生背景,塑造了不同的“性格” 名称 背景与目标 产品定位 Kafka 为了解决 LinkedIn 的日志收集瓶颈,强调吞吐与持久化 更像一个“可持久化的分布式日志系统” RabbitMQ 出自金融通信协议 AMQP 的实现,强调协议标准与广泛适…...
【比赛真题解析】篮球迷
本次给大家分享一道比赛的题目:篮球迷。 洛谷链接:U561543 篮球迷 题目如下: 【题目描述】 众所周知,jimmy是个篮球迷。众所周知,Jimmy非常爱看NBA。 众所周知,Jimmy对NBA冠军球队的获奖年份和队名了如指掌。 所以,Jimmy要告诉你n个冠军球队的名字和获奖年份,并要求你…...

【MATLAB源码-第277期】基于matlab的AF中继系统仿真,AF和直传误码率对比、不同中继位置误码率对比、信道容量、中继功率分配以及终端概率。
操作环境: MATLAB 2022a 1、算法描述 在AF(放大转发)中继通信系统中,信号的传输质量和效率受到多个因素的影响,理解这些因素对于系统的优化至关重要。AF中继通信的基本架构由发射端、中继节点和接收端组成。发射端负…...

webRtc之指定摄像头设备绿屏问题
摘要:最近发现,在使用navigator.mediaDevices.getUserMedia({ deviceId: ‘xxx’}),指定设备的时候,video播放总是绿屏,发现关闭浏览器硬件加速不会出现,但显然这不是一个最好的方案; 播放后张这样 修复后 上代码 指定…...

2023年03月青少年软件编程(图形化)等级考试四级编程题
求和 1.准备工作 (1)保留舞台中的小猫角色和白色背景。 2.功能实现 (1)计算1~100中,可以被3整除的数之和; (2)说出被3整除的数之和。 标准答案: 参考程序&…...

ensp的华为小实验
1.先进行子网划分 2.进行接口的IP地址配置和ospf的简易配置,先做到全网小通 3.进行ospf优化 对区域所有区域域间路由器进行一个汇总 对区域1进行优化 对区域2.3进行nssa设置 4.对ISP的路由进行协议配置 最后ping通5.5.5.5...

ragflow报错:KeyError: ‘\n “序号“‘
环境: ragflowv 0.17.2 问题描述: ragflow报错:KeyError: ‘\n “序号”’ **1. 推荐表(输出json格式)** [{"},{},{"},{} ]raceback (most recent call last): May 08 20:06:09 VM-0-2-ubuntu ragflow-s…...
Java大数据可视化在城市空气质量监测与污染溯源中的应用:GIS与实时数据流的技术融合
随着城市化进程加速,空气质量监测与污染溯源成为智慧城市建设的核心议题。传统监测手段受限于数据离散性、分析滞后性及可视化能力不足,难以支撑实时决策。2025年4月27日发布的《Java大数据可视化在城市空气质量监测与污染溯源中的应用》一文,…...

FHE与后量子密码学
1. 引言 近年来,关于 后量子密码学(PQC, Post-Quantum Cryptography) 的讨论愈发热烈。这是因为安全专家担心,一旦有人成功研发出量子计算机,会发生什么可怕的事情。由于 Shor 算法的存在,量子计算机将能够…...
Flask 调试的时候进入main函数两次
在 Flask 开启 Debug 模式时,程序会因为自动重载(reloader)的机制而启动两个进程,导致if __name__ __main__底层的程序代码被执行两次。以下说明其原理与常见解法。 Flask Debug 模式下自动重载机制 Flask 使用的底层服务器 Wer…...
cv_area_center()
主题 用opencv实现了halcon中area_center算子的功能, 返回region的面积,中心的行坐标和中心的列坐标 代码很简单 def cv_area_center(region):area[]row []col []for re in region:retval cv2.moments(re)area.append(retval[m00])row.append(int(r…...

CSS: 选择器与三大特性
标签选择器 标签选择器就是选择一些HTML的不同标签,由于它们的标签需求不同,所以CSS需要设置标签去选择它们,为满足它们的需求给予对应的属性 基础选择器 标签选择器 <!DOCTYPE html> <head><title>HOME</title>…...
2505d,d的借用检查器
void func(scope ref int*) {}unique(int*) a ...; assert(a !is null);unique(int*) b a; assert(a is null); assert(b !is null);func(b); // ok用live作为检查器,不必有断定了. int* a ...; int* b a; // 所有权转至b *a 3; // 不能再用a.编译器保证约束指针. live…...
力扣-2.两数相加
题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都…...

M0基础篇之ADC
本节课使用到的例程 一、Single模式例程基本配置的解释 在例程中我们只使用到了PA25这一个通道,因此我们使用的是Single这个模式,也就是我们在配置模式的时候使用的是单一转换。 进行多个通道的测量我们可以使用Sequence这个模式。 二、Single模式例程基…...