比较器 Comaprator,经典的多元素协同排序,大厂笔试必考1题
提示:在大厂的笔试题中,贪心的题目,经常考,比如华为,字节,美团等等,都会考协同排序,比较器来玩
啥是比较器协同排序
就你自己设计的数据结构,不是系统基础类,比如学生类Student
学生有姓名,学号,年龄等属性
public static class Student{
private String name;
private String ID;
private int age;
public Student(String n, String i, int a){
name = n;
ID = i;
age = a;
}
}
现在需要你给一堆学生排序,排序规则是:
(1)当年龄不同时,按照年龄升序排序
(2)当年龄相同时,按照学号升序排序
——这就是我们讲的协同排序
比较器本质
我们先看比较器,怎么给其中1个属性排序
比如年龄:
写一个自己的比较器:myComparator2,执行一个接口:Comparator
里面操作的数据类型是Student
——如果比较函数是:比较2个Student :o2和o1:
return o2.age - o1.age;//根据年龄降序排
这等价于:降序排序,o2排在前面。
本质是:
(1)如果o2.age - o1.age < 0 ,则返回-1;代表o2.age小于o1.age
(2)o2.age - o1.age = 0,则返回0,代表o2.age=o1.age
(3)o2.age - o1.age > 0,则返回1,代表o2.ag>于o1.age
面对return o2.age - o1.age;//根据年龄降序排
此时我们的o2是排在o1前面的,我们要让比较器恰好返回1,故是降序排列。
——如果比较函数是:比较2个Student :o1和o2:
return o1.age - o2.age;//根据年龄降升序排
这等价于:降序排序,o2排在前面。
本质是:
(1)如果o1.age - o2.age < 0 ,则返回-1;代表o1.age小于o2.age
(2)o1.age - o2.age = 0,则返回0,代表o1.age=o2.age
(3)o1.age - o2.age > 0,则返回1,代表o1.ag>于o2.age
面对return o1.age - o2.age;//根据年龄降升序排
此时我们的o1是排在o2前面的,我们要让比较器恰好返回-1,故是升序排列。
//降序排列比较器的写法
public static class myComparator2 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2){
return o2.age - o1.age;//根据年龄降序排
}
}
//升序排列比较器的写法
public static class upComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2){
return o1.age - o2.age;
}
}
我们怎么用呢?
有几个学生,我们来个根据升序和降序排序
//Student类型的
public static void test2(){
Student stu = new Student("a", "1", 1);
Student stu2 = new Student("b", "2", 2);
Student stu3 = new Student("c", "3", 3);
PriorityQueue<Student> heap = new PriorityQueue<>(new myComparator2());
PriorityQueue<Student> heap2 = new PriorityQueue<>(new upComparator());
//挨个加入大根堆,降序,就是大根堆,默认小根堆
heap.add(stu);
heap.add(stu2);
heap.add(stu3);
System.out.println(heap.peek().age);//头顶的年龄
//这个大根堆,小根堆的思想要记住,堆结构比堆排序重要
//小根堆
heap2.add(stu);
heap2.add(stu2);
heap2.add(stu3);
System.out.println(heap2.peek().age);//头顶的年龄
}
public static void main(String[] args) {
test2();
}
结果:
3
1
基础数据类型也可以写
比如int的降序
//单存的int类型的降序比较器
public static class myComparator implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;//降序
}
}
public static void test1(){
PriorityQueue<Integer> heap = new PriorityQueue<>(new myComparator());
//这里new就是提醒为大根堆
heap.add(1);
heap.add(2);
heap.add(3);
System.out.println(heap.peek());
}
协同比较器排序
现在需要你给一堆学生排序,排序规则是:
(1)当年龄不同时,按照年龄升序排序
(2)当年龄相同时,按照学号升序排序
——这就是我们讲的协同排序
联合的话,直接写一个比较器也就可以了,这么写
分条件返回
当(1)满足,就返回(1)
当(1)不满足,咱再写(2)
//复习协同比较器排序;
//(1)当年龄不同时,按照年龄升序排序
//(2)当年龄相同时,按照学号升序排序
public static class cooperateComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2){
return o1.age != o2.age ? o1.age - o2.age : o1.ID.compareTo(o2.ID);
}
}
//测试
public static void test3(){
Student stu = new Student("a", "20181214192", 1);
Student stu2 = new Student("b", "20181214193", 2);
Student stu3 = new Student("c", "20181214190", 2);
PriorityQueue<Student> heap = new PriorityQueue<>(new cooperateComparator());
//协同排序
heap.add(stu);
heap.add(stu2);
heap.add(stu3);
while (!heap.isEmpty()){
System.out.println(heap.poll().name);
}
}
public static void main(String[] args) {
// test2();
test3();
}
测试:
a
c
b
显然,a用户,它的年龄最小,故,排在最左
b和c年龄一样,但是c的ID字符串的字典序更小,所以就c排在b前面
总结
提示:重要经验:
1)比较器的本质,返回3种值,-1,0,1,但是o1在前,认为是升序,小根堆,o2在前,认为是降序,大根堆
2)在互联网大厂的笔试中,经常考比较器,尤其想华为这种个,需要配置硬件资源,服务器的各种参数选择有先后顺序,就需要设计协同排序,协同比较器就是最常用的数据结构。