Comparator< T >接口实现自定义规则排序
一、案例Demo
先上一段代码(出自黑马程序员在B站的java基础课程)
public class Demo_Student {
public static void main(String[] args) {
Student s1 = new Student("张三" , 100 , 98);
Student s2 = new Student("李四" , 80 , 95);
Student s3 = new Student("王五" , 96 , 92);
Student s4 = new Student("赵六" , 99 , 99);
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getTotal() - s1.getTotal();//降序排列
num = (num == 0) ? s1.getName().compareTo(s2.getName()) : num;
return num;
}
});
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for (Student stu : ts){
System.out.println(stu.getName() + " 总分:" + stu.getTotal() +
" 语文:" + stu.getChineseScore() + " 数学:" + stu.getMathScore());
}
}
}
- Demo基本的功能:
1、将Student对象装入TreeSet集合中;
2、对集合内部的Student对象元素进行自定义排序规则的排序;
3、输出排序后的集合元素。
二、案例解析
- 对于上述提及的,Demo的三个部分的功能,最关键的毫无疑问是第②步,如何对TreeSet集合内部的Student对象元素进行自定义规则的排序。
- 所以这里就涉及到:创建TreeSet对象的时候,new Comparator< T >()对象,并重写其compare()方法
- 而实现自定义规则排序的关键,就是重写Comparator接口的compare()方法
三、compare方法的剖析(重)
以Demo为例:首先根据总成绩(getTotal)降序排序,即从大到小;如果总分相同,则按照姓名的字母顺序,由小到大排序。那么应该怎样设计重写compare方法呢?
对于重写compare(),有两点理解至关重要:①两个参数o1 o2 ②int类型的返回值
@Override
public int compare(Student s1, Student s2) {
//Demo中仅仅是将参数名修改为s1 s2,不影响功能
int num = s2.getTotal() - s1.getTotal();
num = (num == 0) ? s1.getName().compareTo(s2.getName()) : num;
return num;
}
1、参数o1 o2(s1 s2),代表了在集合中顺序存储着的两个元素,o1在前,o2在后。
2、int类型的返回值,如果为正值,则在集合中对o1 o2的位置进行互换;为负则保持不变。(正则为真,执行互换;负责为假,不予执行)
- 第一行语句:s2的总分与s1的总分相减,赋值给num;如果就此打住,紧接着return,那么如果s2更大,则num为正,返回值为正,s1 s2交换,大的元素永远在前;如果s2更小,num为负,s1 s2不交换,完成成绩的降序排序!
- 第二行语句:如果s1 s2总分相同(如张三和赵六),则num根据s1 s2的姓名比较结果进行排序。注:compareTo:左小右大为负,右大左小为正,左右相等为零;至此,完成姓名升序排序!
四、总结
简而言之:compare内部不管做了多么复杂的运算,制定了多么复杂的规则,最后排序的结果(o1 o2是否交换)永远只取决于返回值的正负情况,所以在设计我们自己的集合排序规则的时候,这也是我们考虑的最核心问题。
五、一些拓展
1、类似的,通过new Comparator接口并重写其compare方法的方式,完成自定义排序的其他几种情况(个人经验,并不全面):
- ArrayList的sort()方法:(巩固例题)
ArrayList对象名.sort(new Comparator< T >(){ … });
- Collections.sort()方法:
Collections.sort(List< T > list,Comparator<? super T> c);
- Arrays.sort()方法:
Arrays.sort(T[] a,Comparator<? super T> c);
2、巩固例题:算法提高 最小字符串
-
问题描述
给定一些字符串(只包含小写字母),要求将他们串起来构成一个字典序最小的字符串。 -
输入格式
第一行T,表示有T组数据。
接下来T组数据
每组第一行一个正整数n,表示字符串个数。
接下来n行,每行一个字符串(长度不超过100)。 -
输出格式
T行,每行一个字符串。 -
样例输入
1
3
a
b
c -
样例输出
abc
代码如下:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//总共的字符串数
for (int i = 0 ; i < n ; i++){
int num = sc.nextInt();//接下来输入几行
ArrayList<String> list = new ArrayList<String>();//使用ArrayList存储所有输入的字符
for (int j = 0 ; j < num ; j++){
String str = sc.next();
list.add(str);//将字符装入List
}
list.sort(new Comparator<String>() {//调用ArrayList的sort()方法并且重写Comparator
@Override
public int compare(String o1, String o2) {
//例如:b和ba,字典序b<ba,但是从大局考虑,ba应排在前面
String temp1 = o1 + o2;
String temp2 = o2 + o1;//代表 “o2在前,o1在后” 的状态
//若返回负数,则不交换,o1 o2目前状态(o1前o2后)满足整体字符串的字典序最小
return temp1.compareTo(temp2);
}
});
for (int j = 0 ; j < num ; j++){//输出一组字符串
System.out.print(list.get(j));
}
System.out.println();
}
sc.close();
}
}