有一个类,存储学生信息,第一个成员是年龄,第二个是身高,有一个学生容器数组,按照自定义规则进行排序,首先按照年龄升序排序,年龄相同的,按照身高升序排序,下面是示例代码:
import java.util.Arrays;
import java.util.Comparator;
class Student {
private int age;
private double height;
public Student(int age, double height) {
this.age = age;
this.height = height;
}
public int getAge() {
return age;
}
public double getHeight() {
return height;
}
}
public class Students {
public static void main(String[] args) {
Student[] students = new Student[5];
students[0] = new Student(20, 170.5);
students[1] = new Student(18, 165.6);
students[2] = new Student(20, 170.4);
students[3] = new Student(19, 165.4);
students[4] = new Student(18, 165.5);
// 使用自定义规则对学生数组进行排序
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 首先按照年龄升序排序
int ageComparison = Integer.compare(s1.getAge(), s2.getAge());
if (ageComparison != 0) {
return ageComparison;
}
// 年龄相同,按照身高升序排序
return Double.compare(s1.getHeight(), s2.getHeight());
}
});
// 打印排序后的学生信息
for (Student student : students) {
System.out.println("Age: " + student.getAge() + ", Height: " + student.getHeight());
}
}
}
输出:
Age: 18, Height: 165.5
Age: 18, Height: 165.6
Age: 19, Height: 165.4
Age: 20, Height: 170.4
Age: 20, Height: 170.5
注意其中在声明比较规则的匿名内部类时我们使用了
return Double.compare(s1.getHeight(), s2.getHeight());
而不是
return (int)(s1.getHeight()- s2.getHeight());
为什么呢,首先我们知道Array的sort函数在升序时的规则为,当左边的数大于右边的数应当返回正整数,反之返回负整数,如果相等则返回0。而当俩个浮点数的差不到1时,强转int得到的值为0,会导致错误排序,而java已经考虑了这点给我们提供了方便的比较函数。
可以打开库函数看看Double.compare的逻辑:
public static int compare(double d1, double d2) {
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
// Cannot use doubleToRawLongBits because of possibility of NaNs.
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
而且不仅仅是浮点数,在整数类型排序时也最好使用Integer.compare,因为自己手动对两个int数据相减的话容易导致数据超范围。
另外,注意我们在上面使用的排序api是Arrays.sort(),还有一种常用的排序api是Collections.sort(),它们主要区别在于它们所操作的数据类型和实现方式:
数据类型:
Arrays.sort(): 这个方法是针对数组的排序。它可以用于基本数据类型数组(如 int[]、double[] 等)和对象类型数组(如 String[]、Integer[] 等)。
Collections.sort(): 这个方法是针对集合类的排序。它只能用于实现了 List 接口的集合,例如 ArrayList、LinkedList 等。
实现方式:
Arrays.sort(): 对数组排序采用的是经过优化的快速排序(Dual-Pivot Quicksort)算法。在大多数情况下,它比较高效,并且具有稳定的排序性能。
Collections.sort(): 对集合排序采用的是归并排序(Merge Sort)算法。尽管归并排序在大多数情况下也是高效的,但它需要额外的空间来执行排序操作。由于集合是动态数据结构,可能需要频繁地进行内存分配和释放,因此在排序大型集合时可能稍慢一些。