9.5.1排序和洗牌1
静态方法Collections.sort可以对实现了List接口的集合进行排序。
List<String> staff = new LinkedList<>();
fill collection
Collections.sort(staff);
该方法假定List的元素实现了Comparable接口。如果想用其他的顺序进行排序,可以使用List接口的sort方法,它接收一个Comparator参数。你可以按照薪水对雇员List进行排序:
staff.sort(Comparator.comparingDouble(Employee::getSalary));
如果你想对一个List进行降序排列,可以使用简便方法Comparator.reverseOrder(),它返回一个Comparator,这个Comparator使用b.compare(a)来代替a.compare(b)。例如:
staff.sort(Comparator.reverseOrder());
对staff中的元素进行反序排列,而对应的正序排列利用staff中元素的compareTo方法进行比较。类型地,
staff.sort(Comparator.comparingDouble(Employee::getSalary).reversed());
按薪水进行降序排序。
你可能想知道sort方法是如何排序一个List的。通常,你在算法教程里看到的排序算法例题都是作用于数组,并且依赖于元素的随机访问。但是,对LinkedList进行随机访问是低效的。实际上你可以使用一种归并排序算法高效地处理LinkedList。但是Java编程语言并没有采用归并排序。Java只是简单粗暴地把所有元素倒进一个数组,对数组进行排序,然后复制排序后的数组到原来的List中。
集合库中的sort方法虽然不如快排高效,但是有一个优点:稳定性,即它不会交换相等的元素。举个例子说明这个优点:假设你已经有了一个按名字排序的雇员列表,现在你对这个列表按薪水排序。薪水相等的雇员会怎么样呢?在具有稳定性的排序算法中,名字的顺序仍然保留。换言之,我们最后得到的是先按薪水,后按名字排序的列表。
集合类并不需要实现所有的“可选”方法,所以接收集合对象作为参数的所有方法都需要明确它是否可以正确处理某种集合对象。(换言之,这个方法需要对它的参数施加限制,并不是所有类型的集合都可用)。例如,你当然不能传递unmodifiableList给sort算法。按照文档的说法,该List必须是modifiable的,但不必是resizable的。
这些术语的定义如下
如果一个List支持set操作,则它是modifiable的
如果一个List支持add和remove操作,则它是resizable的
Collections还有一个算法shuffle,它的行为与sort刚好相反,随机改变List中元素的顺序。例如:
ArrayList<Card> cards = ...;
Collections.shuffle(cards);
同sort一样,对不能随机访问的List(没有实现RandomAccess接口)进行洗牌的时候,也是通过一个数组来倒腾的。
程序Listing 9.7用1-49这49个Integer填充一个ArrayList,然后对该list洗牌,并抽出前6个值,最后把这6个值进行排序并打印。
//Listing 9.7
import java.util.*;
public class ShuffleTest{
public static void main(String[] args){
List<Integer> numbers = new ArrayList<>();
for(int i = 1; i <=49; i++)
numbers.add(i);
Collections.shuffle(numbers);
List<Integer> winningCombination = numbers.subList(0,6);
Collections.sort(winningCombination);
System.out.println(winningCombination);
}
}
java.util.Collections (from version 1.2)
方法 | 描述 |
---|---|
static <T extends Comparable<? super T>> void sort(List<T> elements) | 使用一个stable算法对list中的元素进行排序,性能O(n*logn) |
static void shuffle(List<?> elements) | |
static void shuffle(List<?> elements, Random r) | 随机洗牌List,性能O(n*a(n) ),其中n为list长度,a(n)为随机访问一个元素的平均时间 |
java.util.List<E> (from version 1.2)
方法 | 描述 | 版本 |
---|---|---|
default void sort(Comparator<? super T> comparator) | 使用给定的Comparator排序list | 8 |
java.util.Comparator<T> (from version 1.2)
static <T extends Comparable<? super T >> Comparator<T> reverseOrder() | 返回一个与Comparable接口提供的比较顺序相反的比较器 | 8 |
---|---|---|
default Comparator<T> reversed() | 返回一个与该比较器顺序相反的比较器 | 8 |