关于Comparable、Comparator接口返回值决定顺序的问题

Comparable和Comparator接口都是实现集合中元素的比较、排序的,下面先简单介绍下他们的用法。

1. 使用示例

public class Person {private String name;private Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Person o) {return  this.age - o.age;}
}
        ArrayList<Person> list = new ArrayList<>();list.add(new Person("朱一百",100));list.add(new Person("朱八零",80));list.add(new Person("朱八一",81));list.add(new Person("朱九零",90));list.add(new Person("朱八二",82));list.add(new Person("朱七七",77));list.add(new Person("朱八八",88));list.add(new Person("朱重八",88));

1.1 Comparable

public class Person  implements Comparable<Person>{......@Overridepublic int compareTo(Person o) {if (this.getAge() < o.getAge()) {return -1;} else if (this.getAge() > o.getAge()) {return 1;} else {return this.getName().compareTo(o.getName());}}
}
public class ComparableTest {public static void main(String[] args) {......Collections.sort(list);list.forEach(System.out::println);}
}

1.2 Comparator

public class PersonComparator  implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {if (o1.getAge() < o2.getAge()) {return -1;} else if (o1.getAge() > o2.getAge()) {return 1;} else {return o1.getName().compareTo(o2.getName());}}
}
public class ComparatorTest {public static void main(String[] args) {......Collections.sort(list,new PersonComparator());list.forEach(System.out::println);}
}

以上的两个例子输出的结果如下所示:

Person{name='朱七七', age=77}
Person{name='朱八零', age=80}
Person{name='朱八一', age=81}
Person{name='朱八二', age=82}
Person{name='朱八八', age=88}
Person{name='朱啊八', age=88}
Person{name='朱九零', age=90}
Person{name='朱一百', age=100}

按照年龄升序排列,年龄相同时按照姓名升序排序。

2. 关于返回结果-1 0 1 和排序的关系

在上面的例子中我们分别实现了compare()compareTo()对集合继续宁排序,但是我们想知道方法返回-1、0、1对集合排序的关系。

2.1 Comparable

List#sort() =>ArrayList#sort() => Arrays#sort() ⇒ ComparableTimSort#sort() ⇒ ComparableTimSort.#countRunAndMakeAscending()
ArrayList#sort()
可以看到到Comparator c == null 时进入sort() 方法,当我们实现Comparator进行排序时,进入的方法就应该是 TimSort.sort()
Arrays#sort()
ComparableTimSort#sort()
ComparableTimSort.#countRunAndMakeAscending()
countRunAndMakeAscending方法如下:

    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {assert lo < hi;int runHi = lo + 1;if (runHi == hi)return 1;if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descendingwhile (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)runHi++;reverseRange(a, lo, runHi);} else {                              // Ascendingwhile (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)runHi++;}return runHi - lo;}

如果当前子序列是"递减"的,也就是 a[runHi] 小于 a[lo],那么需要找到连续"递减"的子序列的结束位置 runHi。直到找到第一个不满足"递减"条件的元素。然后,调用 reverseRange 方法将"递减"的子序列反转为"递增"的子序列。

如果当前子序列是"递增"的,也就是 a[runHi] 大于等于 a[lo],那么需要找到连续"递增"的子序列的结束位置 runHi。
最后,返回 runHi - lo,即子序列的长度。

    private static void binarySort(Object[] a, int lo, int hi, int start) {assert lo <= start && start <= hi;if (start == lo)start++;for ( ; start < hi; start++) {Comparable pivot = (Comparable) a[start];int left = lo;int right = start;assert left <= right;/** Invariants:*   pivot >= all in [lo, left).*   pivot <  all in [right, start).*/while (left < right) {int mid = (left + right) >>> 1;// pivot元素的索引比a[mid]的索引大// pivot元素在数组中比a[mid]靠后if (pivot.compareTo(a[mid]) < 0)right = mid;elseleft = mid + 1;}assert left == right;int n = start - left;  // The number of elements to move// Switch is just an optimization for arraycopy in default caseswitch (n) {case 2:  a[left + 2] = a[left + 1];case 1:  a[left + 1] = a[left];break;default: System.arraycopy(a, left, a, left + 1, n);}a[left] = pivot;}}

这个方法做的事情如下:

  1. 经过countRunAndMakeAscending()方法 start位置之前的集合是有序的,于是start位置开始,pivot=array[start],使用二分查找法对start之前已经有序的数组比对,从start下标开始从后往前找,找到start下标之前第一个大于array[start]的元素下标index;
  2. 根据要移动的步数n = start - left做了优化,但是目的是将[left, start-1]范围内的数组值都向后移动一位,放在 [left+1~start],再把pivot的值赋予array[left];
  3. start++,循环执行以上步骤直到数组结束

总结

我们实现的compareTo()方法返回-1 0 1 和集合的排序是升序或者降序没有直接的关系,在上面的方法我们可以看到的是compareTo()返回会导致如下结果:

  1. 返回-1说明两个比较的元素需要交换位置
  2. 但会0或者1不需要交换两个元素的位置

所以我们应该能比较清楚的知道返回-1 0 1 给我们排序带来的效果了,比如上方的pivot.compareTo(a[mid]) pivot在数组中比a[mid]靠后,当 if (this.getAge() < o.getAge()) {return -1}; 我们希望pivot的age小于a[mid]时交换位置,最后排序的结果就是年龄的升序,如果if (this.getAge() < o.getAge()) {return 1};最后排序的结果就是年龄的降序

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【UE】Texture Coordinate 材质节点

目录 一、简介 二、属性介绍 &#xff08;1&#xff09;参数&#xff1a;U平铺 &#xff08;2&#xff09;参数&#xff1a;V平铺 &#xff08;3&#xff09;参数&#xff1a;解除镜像U &#xff08;4&#xff09;参数&#xff1a;解除镜像V 三、 节点构成原理 四、初级…

基于YOLOV8模型的农作机器和行人目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOV8模型的农作机器和行人目标检测系统可用于日常生活中检测与定位农作机和行人目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标…

统一网关Gateway

文章目录 概览网关的作用搭建网关断言工厂路由过滤器全局过滤器案例 过滤器执行顺序跨域问题 概览 网关的作用 搭建网关 断言工厂 路由过滤器 全局过滤器 案例 过滤器执行顺序 跨域问题

论文阅读:Distortion-Free Wide-Angle Portraits on Camera Phones

论文阅读&#xff1a;Distortion-Free Wide-Angle Portraits on Camera Phones 今天介绍一篇谷歌 2019 年的论文&#xff0c;是关于广角畸变校正的。 Abstract 广角摄影&#xff0c;可以带来不一样的摄影体验&#xff0c;因为广角的 FOV 更大&#xff0c;所以能将更多的内容…

单片机的ADC

如何理解ADC。ADC就是将模拟量转换成数字量的过程&#xff0c;就是转换为计算机所能存储的0和1序列&#xff0c;比如将模拟量转换为一个字节&#xff0c;所以这个字节的大小要能反应模拟量的大小&#xff0c;比如一个0-5V的电压测量量&#xff08;外部输入电压最小0V,最大为5V&…

websocket基础

下面就以代码来进行说明 1&#xff0c;先导入websocket依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency> 2.编写websocket相关bean管理配置 Config…

Unity生命周期函数

1、Awake 当对象&#xff08;自己这个类对象&#xff0c;就是这个脚本&#xff09;被创建时 才会调用该生命周期函数 类似构造函数的存在 我们可以在一个类对象创建时进行一些初始化操作 2、OnEnable 失活激活&#xff08;这个勾&#xff09; 想要当一个对象&#xff08;游戏…

【杂言】写在研究生开学季

这两天搬进了深研院的宿舍&#xff0c;比中南的本科宿舍好很多&#xff0c;所以个人还算满意。受台风 “苏拉” 的影响&#xff0c;原本的迎新计划全部打乱&#xff0c;导致我现在都还没报道。刚开学的半个月将被各类讲座、体检以及入学教育等活动占满&#xff0c;之后又是比较…

ZDH-权限模块

本次介绍基于ZDH v5.1.2版本 目录 项目源码 预览地址 安装包下载地址 ZDH权限模块 ZDH权限模块-重要名词划分 ZDH权限模块-菜单管理 ZDH权限模块-角色管理 ZDH权限模块-用户配置 ZDH权限模块-权限申请 项目源码 zdh_web: GitHub - zhaoyachao/zdh_web: 大数据采集,抽…

ROS 2官方文档(基于humble版本)学习笔记(一)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;一&#xff09; 一、安装ROS 2二、按教程学习1.CLI 工具配置环境使用turtlesim&#xff0c;ros2和rqt安装 turtlesim启动 turtlesim使用 turtlesim安装 rqt使用 rqt重映射关闭turtlesim 由于市面上专门…

关于 MySQL、PostgresSQL、Mariadb 数据库2038千年虫问题

MySQL 测试时间&#xff1a;2023-8 启动MySQL服务后&#xff0c;将系统时间调制2038年01月19日03时14分07秒之后的日期&#xff0c;发现MySQL服务自动停止。 根据最新的MySQL源码&#xff08;mysql-8.1.0&#xff09;分析&#xff0c;sql/sql_parse.cc中依然存在2038年千年虫…

java八股文面试[多线程]——Synchronized优化手段:锁膨胀、锁消除、锁粗化和自适应自旋锁

1.锁膨胀 &#xff08;就是锁升级&#xff09; 我们先来回顾一下锁膨胀对 synchronized 性能的影响&#xff0c;所谓的锁膨胀是指 synchronized 从无锁升级到偏向锁&#xff0c;再到轻量级锁&#xff0c;最后到重量级锁的过程&#xff0c;它叫锁膨胀也叫锁升级。 JDK 1.6 之前…

MATLAB中mod函数转化为C语言

背景 有项目算法使用matlab中mod函数进行运算&#xff0c;这里需要将转化为C语言&#xff0c;从而模拟算法运行&#xff0c;将算法移植到qt。 MATLAB中mod简单介绍 语法 b mod(a,m) 说明 b mod(a,m) 返回 a 除以 m 后的余数&#xff0c;其中 a 是被除数&#xff0c;m 是…

详解Vue中的render: h => h(App)

声明:只是记录&#xff0c;会有错误&#xff0c;谨慎阅读 我们用脚手架初始化工程的时候&#xff0c;main.js的代码如下 import Vue from vue import App from ./App.vueVue.config.productionTip falsenew Vue({// 把app组件放入容器中render: h > h(App), }).$mount(#ap…

FPGA 学习笔记:Vivado 工程管理技巧

前言 当前使用 Xilinx 的 FPGA,所以需要熟悉 Xilinx FPGA 的 开发利器 Vivado 的工程管理方法 这里初步列举一些实际 Xilinx FPGA 开发基于 Vivado 的项目使用到的工程的管理技巧 代码管理 做过嵌入式软件或者其他软件开发的工程技术人员,都会想到使用代码管理工具,如 SVN 、…

Python入门教程 - 基本语法 (一)

目录 一、注释 二、Python的六种数据类型 三、字符串、数字 控制台输出练习 四、变量及基本运算 五、type()语句查看数据的类型 六、字符串的3种不同定义方式 七、数据类型之间的转换 八、标识符命名规则规范 九、算数运算符 十、赋值运算符 十一、字符串扩展 11.1…

AtCoder Beginner Contest 318

目录 A - Full Moon B - Overlapping sheets C - Blue Spring D - General Weighted Max Matching E - Sandwiches F - Octopus A - Full Moon #include<bits/stdc.h> using namespace std; const int N1e65; typedef long long ll ; const int maxv4e65; typedef …

mac使用VsCode远程连接服务器总是自动断开并要求输入密码的解决办法

在mac中使用vscode远程连接服务器&#xff0c;时常会出现自动断开并要求重新输入服务器密码的问题&#xff0c;接下来让我们来解决它&#xff1a; 1、首先&#xff0c;在本地创建公钥&#xff1a; ssh-keygen 这条命令执行之后&#xff0c;出现提示直接回车即可&#xff1b;直…

内网穿透神器-frp的概念,搭建和使用,方便访问内网服务

FRP概念 FRP是什么(借助官网的描述)&#xff1f; frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 为什么是用FR…

CSS流光按钮-圆形

主要思路 仅保留一条边框 border-radius 50%drop-shadow动画 animation keyframes 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, …