Java中的Sort排序问题
作者:v2hoping
Java中Sort排序是非常常用的方法,这一章我们主要来认识一下Sort的用法和相关的实现。
一、数组Sort排序
升序排序,直接使用Arrays.Sort方法,例如:
int[] array = {10, 3, 6, 1, 4, 5, 9}; //正序排序 Arrays.sort(array);//会检查数组个数大于286且连续性好就使用归并排序,若小于47使用插入排序,其余情况使用双轴快速排序 System.out.println("升序排序:"); for (int num : array) { System.out.println(num); }
降序排序,对于只输出数组的情况,可以倒叙循环访问,例如:
//倒序排序 //(1)由于不提供倒排方法,你可以倒叙输出 System.out.println("降序输出:"); for (int i = array.length - 1; i >= 0; i--) { System.out.println(array[i]); }
降序排序,对于需要使用数组 的情况,可以创建一个新的数组,然后倒叙访问赋值,例如:
//(2)或者创建一个新的数组,倒叙保存到新数组 int[] descArray = new int[array.length]; for (int i = 0; i < array.length; i++) { descArray[i] = array[array.length - i - 1]; } System.out.println("新数组降序输出:"); for (int num : descArray) { System.out.println(num); }
降序排序,可以先将数组转为集合,然后使用Collections.reverse()反转集合,但是对于非引用类型,不可以使用Arrays.asList(),因为int[]会被当作一个类型,而不是数组。
所以可以使用Guava的Ints.asList()方法实现,该转换后的集合,实现了List接口的方法,直接将数组转入内部的数组变量,需要注意它并没有实现数组的操作方法,例如调用add会报错:
转换和排序例如:
//(3)或者使用Guava来实现 List<Integer> integersList = Ints.asList(array); Collections.reverse(integersList);//冒泡交换 System.out.println("Guava降序输出:"); for (int num : integersList) { System.out.println(num); }
转后的集合类是Guava中的IntArrayAsList,其类UML图如下:
二、集合Sort排序—包装类
本小节主要是对jdk类库中的包装类排序,例如:Integer、String等,这些类都已经重写了Compare方法,都有默认排序规则,例如对于Integer类型会比较其包装的值类型大小,对于String类型会以长度最小字符串为基准,逐一比较相同位置字符的ASCII码大小,如果都相同则比较字符串的长度。
以Integer为例子,升序排序:
//Integer集合,正序排序 List<Integer> list = new ArrayList<Integer>(Arrays.asList(10, 3, 6, 1, 4, 5, 9)); Collections.sort(list); System.out.println("集合正序排序:"); for (Integer num : list) { System.out.println(num); }
返回:
集合正序排序: 1 3 4 5 6 9 10
降序排序:
//倒叙排序 Comparator<Integer> reverseComparator = Collections.reverseOrder(); Collections.sort(list, reverseComparator); System.out.println("集合倒叙排序:"); for (Integer num : list) { System.out.println(num); }
返回:
集合倒叙排序: 10 9 6 5 4 3 1
三、集合Sort排序—自定义对象
除了两节所描述的情况,我们还会遇到对于自定义类排序的情况,例如我们现在有一个学生对象,想要根据年龄对其进行排序,学生类Student如下:
public class Student { private String name; private Integer age; public Student(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; } /** * 为了更好显示数据,我们重写toString()方法. * @return 显示变量的字符串 */ @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
(1) 第一种方式,是实现Comparable接口,重写接口方法。
该CompareTo()方法,如果指定的数与参数相等返回0;如果指定的数小于参数返回 -1;如果指定的数大于参数返回 1。
对于排序来讲,你可以认为当返回1时,指定的数和参数会进行交换,而非1时则不变,指定数可以当作原本的数组中靠前的数,而参数可以当作靠后的数,又因为只有靠前数大于靠后数时才返回1,所以大的会被放到后面,此时升序排序(方便记忆)。以此类推,倒序情况则相反。
升序排序,比Student类增加了Comparable接口,并实现升序排序:
public class StudentAsc implements Comparable<StudentAsc> { private String name; private Integer age; public StudentAsc(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; } public int compareTo(StudentAsc o) { if(null == this.age) { return -1; } if(null == o.getAge()) { return 1; } return this.age.compareTo(o.getAge()); } @Override public String toString() { return "StudentAsc{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
方法调用:
//正序排序,年龄为null时为小 StudentAsc studentWang = new StudentAsc("王小二", 10); StudentAsc studentZhang = new StudentAsc("张三", 1); StudentAsc studentGou = new StudentAsc("狗子", 99); StudentAsc studentZhao = new StudentAsc("赵六", 40); StudentAsc studentLi = new StudentAsc("李四", null); List<StudentAsc> studentAscs = new ArrayList<StudentAsc>(Arrays.asList(studentWang, studentZhang, studentGou, studentZhao, studentLi)); Collections.sort(studentAscs); System.out.println("自定义对象,升序排序:"); for(StudentAsc studentAsc : studentAscs) { System.out.println(studentAsc.toString()); }
返回:
自定义对象,升序排序: Student{name='李四', age=null} Student{name='张三', age=1} Student{name='王小二', age=10} Student{name='赵六', age=40} Student{name='狗子', age=99}
降序排序,比Student类增加了Comparable接口,并实现倒序排序:
public class StudentDesc implements Comparable<StudentDesc> { private String name; private Integer age; public StudentDesc(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; } public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); } public int compareTo(StudentDesc o) { if(null == this.age) { return 1; } if(null == o.getAge()) { return -1; } return o.age.compareTo(this.getAge()); } @Override public String toString() { return "StudentDesc{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
方法调用:
//降叙排序,年龄为null时为最大 StudentDesc studentWang = new StudentDesc("王小二", 10); StudentDesc studentZhang = new StudentDesc("张三", 1); StudentDesc studentGou = new StudentDesc("狗子", 99); StudentDesc studentZhao = new StudentDesc("赵六", 40); StudentDesc studentLi = new StudentDesc("李四", null); List<StudentDesc> studentAscs = new ArrayList<StudentDesc>(Arrays.asList(studentWang, studentZhang, studentGou, studentZhao, studentLi)); Collections.sort(studentAscs); System.out.println("自定义对象,降序排序:"); for(StudentDesc studentAsc : studentAscs) { System.out.println(studentAsc.toString()); }
返回:
自定义对象,降序排序: Student{name='狗子', age=99} Student{name='赵六', age=40} Student{name='王小二', age=10} Student{name='张三', age=1} Student{name='李四', age=null}
(2)第二种方式,上面实现Comparable接口的方法并不十分灵活,比如对于一个类,在不同的地方需要使用不同的排序,此时再这样做就会显的十分繁琐。因此我们可以通过Collections.sort(List<T> list, Comparator<? super T> c)方法来实现,例子中,我们使用Student类,例子如下:
升序排序:
//升序排序 Student studentWang = new Student("王小二", 10); Student studentZhang = new Student("张三", 1); Student studentGou = new Student("狗子", 99); Student studentZhao = new Student("赵六", 40); Student studentLi = new Student("李四", null); List<Student> students = new ArrayList<Student>(Arrays.asList(studentWang, studentZhang, studentGou, studentZhao, studentLi)); Collections.sort(students, new Comparator<Student>() { public int compare(Student o1, Student o2) { if(null == o1.getAge()) { return -1; } if(null == o2.getAge()) { return 1; } return o1.getAge().compareTo(o2.getAge()); } }); System.out.println("自定义对象,升序排序:"); for(Student student : students) { System.out.println(student.toString()); }
返回:
自定义对象,升序排序: Student{name='李四', age=null} Student{name='张三', age=1} Student{name='王小二', age=10} Student{name='赵六', age=40} Student{name='狗子', age=99}
降序排序:
//降序排序 Student studentWang = new Student("王小二", 10); Student studentZhang = new Student("张三", 1); Student studentGou = new Student("狗子", 99); Student studentZhao = new Student("赵六", 40); Student studentLi = new Student("李四", null); List<Student> students = new ArrayList<Student>(Arrays.asList(studentWang, studentZhang, studentGou, studentZhao, studentLi)); Collections.sort(students, new Comparator<Student>() { public int compare(Student o1, Student o2) { if(null == o1.getAge()) { return 1; } if(null == o2.getAge()) { return -1; } return o2.getAge().compareTo(o1.getAge()); } }); System.out.println("自定义对象,降序排序:"); for(Student student : students) { System.out.println(student.toString()); }
返回:
自定义对象,降序排序: Student{name='狗子', age=99} Student{name='赵六', age=40} Student{name='王小二', age=10} Student{name='张三', age=1} Student{name='李四', age=null}
总结
至此对数组、包装类集合、自定义集合排序做了总结。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。