【数据结构与算法】2 - 3 Arrays 类
§2-3 Arrays
类
2-3.1 Arrays
类概述及常用方法
Arrays
类位于 java.util
包下,提供了许多操作数组的方法,例如排序和查找。该类中还包含了一个静态工厂方法,允许将数组转换为列表。
由于数组本身并不具有方法,因此操作数组时可以使用 Arrays
类中的方法。该类不可被实例化,但是其所有方法都为静态方法,可供外界在无需实例化的情况下调用。
静态方法:
Arrays
类中对不同类型的数组,对方法进行了多种重载,此处仅以整型数组为例,详见官方帮助文档。
静态方法 | 描述 |
---|---|
String toString() |
返回数组内容的字符串表示 |
int binarySearch(int[] a, int key) int binarySearch(int[] a, int fromIndex, int toIndex, int key) |
使用二分查找算法,查找指定数组中的给定关键字,返回其索引 |
int[] copyOf(int[] original, int newLength) |
拷贝数组,截短或用该类型的默认值扩充(若必要的话),使得新数组具有给定长度 |
int[] copyOfRange(int[] original, int from, int to) |
将原数组的给定范围复制到新数组中 |
void fill(int[] a, int val) |
使用给定的值填充整个数组(所有元素) |
void fill(int[] a, int fromIndex, int toIndex, int val) |
使用给定的值填充数组的给定范围 |
void sort(int[] a) |
升序排序指定数组 |
void sort(int[] a, int fromIndex, int toIndex) |
对给定数组的指定范围作升序排序(左闭右开) |
void sort(T[] a, Comparator<? super T> c) |
使用比较器所推导的排序方式,对指定数组作排序 |
void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c) |
使用比较器所推导的排序方式,对指定数组的指定范围作排序 |
注意:
binarySearch()
方法不仅要求数组有序,且必须为升序排列;binarySearch()
方法查找不存在的关键字时,设该关键字在数组中应当插入的索引为i
(插入点),则其返回- i - 1
;sort()
方法(非比较器方法)所使用的排序算法为 Vladimir Yaroslavskiy, Jon Bentley 和 Joshua Bloch 的双轴快速排序(Dual-pivot Quicksort),这种排序通常比单轴快速排序更快;Comparator<T>
是一个接口,当方法参数传入的是接口,应当传入其实现类对象,通常我们会选择在方法的传入参数处定义一个匿名内部类;Comparator<T>
同时也是一个函数式接口,可使用 Lambda 表达式;
2-3.2 sort()
传入接口(比较器)的重载使用方法
使用须知:
Comparator<T>
是一个函数式接口,作为参数传入时应当传入其实现类对象,或写成 Lambda 表达式;- 由于这个实现类只需要使用一次,因此没有必要为此单独编写一个实现类,可使用内部类的形式传递;
- 该重载方法只能给引用数据类型数组进行排序,若为基本数据类型,则应使用其对应包装类;
接口中的唯一抽象方法:
实现类对象中只需要重写该方法即可。
int compare(T o1, T o2);
底层原理:
首先先来简单地介绍该方法的底层原理。
- 该方法使用直接插入排序 + 二分查找,认为 0 索引处的数据有序,其后所有元素均为无序排列;
- 遍历无序序列,得到无序元素,然后使用二分查找查找该元素的插入点,并将该元素与插入点的数据做比较;
- 比较时会调用
compare()
方法,若返回值为非负数(0 和正数),则表示该元素应当位于插入点后面;若为负数,则该元素应当位于插入点前面; - 对于默认升序排序算法,
compare()
方法返回非负数,表示当前元素较大,应放在后面(为零表示相等,也放在后面);返回负数,表示当前元素较小,应当放在前面; compare()
方法中的两个形参,o1
指的是无序元素,而o2
指的是有序元素;为此,升序排列应当o1 - o2
,降序应当o2 - o1
;
示例:升序排列
//演示序列
//不接受基本数据类型,应当使用包装类
Integer[] arr = {2, 3, 1, 5, 6, 7, 8, 4, 9};
System.out.println("原数组:" + Arrays.toString(arr));
System.out.println("===============");
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println("===============");
System.out.println("排序后:" + Arrays.toString(arr));
降序排列:
//演示序列
//不接受基本数据类型,应当使用包装类
Integer[] arr = {2, 3, 1, 5, 6, 7, 8, 4, 9};
System.out.println("原数组:" + Arrays.toString(arr));
System.out.println("===============");
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println("===============");
System.out.println("排序后:" + Arrays.toString(arr));
2-3.3 Lambda 表达式
函数式编程:函数式编程(functional programming),是一种编程思想。不同于面向对象的编程思想,它忽略了面向对象的复杂语法,强调做什么,而不是谁去做。
Lambda 表达式就是函数式编程思想的体现。
Lambda 表达式:Lambda 表达式是 JDK 8 后支持的一种新的语法形式,其基本语法为:
() -> {}
其中,()
为方法的形参,->
是固定格式,{}
是方法体。
Lambda 表达式特点:可推导,可省略
- 类型声明可选:参数的类型可省略,编译器可统一识别参数值;
- 参数圆括号可选:当参数只有一个时,圆括号可省略;
- 大括号、返回关键字与分号可选:当方法体有且只有一句时,方法体大括号、
return
关键字、分号可省略,若要省略,必须同时一起省略;
使用条件:Lambda 表达式只能用于简化函数式接口的匿名内部类写法。
函数式接口:有且只有一个抽象方法的接口成为函数式接口(functional interface),可用 @FunctionalInterface
注解。
使用 Lambda 表达式简化 compare()
方法:完整的 Lambda 表达式
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o1 - o2;
});
使用进一步简化的 Lambda 表达式简化上述语句:
Arrays.sort(arr, ((o1, o2) -> o1 - o2));
案例演示:使用该重载的 sort()
方法,对字符串数组排序,要求按字符串长度升序排序列。
Arrays.sort(arr, (o1, o2) -> o1.length() - o2.length());