1. Arrays工具类简介:
1) 是Java提供的专门用来操作数组的工具类,里面有一大堆静态方法(算法)来操作数组,低位就相当于C++ STL的<algorithm>库,只不过Arrays里面全部都是操作数组的算法,于此类似的是Collections工具类,里面全部都是操作集合的算法;
2) 里面大致分为两类方法,一类是单线方法(用于单线程处理数组),另一类是多线算法(大多以parallel作为前缀,可以充分利用现代CPU多核并行的特点多线程处理数组,特别是对于那些规模非常庞大的数组);
!!接下来介绍的全部都是Arrays工具类的static静态工具方法;
!!所有的from - to的区间都是左闭右开的!!即[from, to);
!!单线方法:
2. 查找:
1) int binarySearch(type[] a, typekey); // 在数组a中二分查找元素key,返回第一个找到的key的索引
2) int binarySearch(type[] a, int fromIndex, int toIndex, typekey); // 锁定索引范围[from, to)内二分查找
!!二分查找的前提是数组已经升序排列好了,如果key没找到则返回-1;
3. 排序:
1) void sort(type[] a); // 对a升序排列
2) void sort(type[] a, int fromIndex, int toIndex); // 对区间[from, to)升序排列
!!Arrays的sort并没有提供指定降序排列的参数,如果非要降序那就倒序迭代构造一个新的数组了!
4. 相等比较:boolean equals(type[] a, type[] a2); // 只有两个数组长度相等,并且每个元素也对应相等时才会返回true
!!对于排序、查找、相等比较,如果数组元素的类型是自定义类型则必须要实现compareTo方法可以让这些算法对数组元素进行比较才行!和C++的<、==重载的道理是一样的;
4. 拷贝:
1) type[] copyOf(type[] original, int length); // 赋值original数组的前length个元素形成一个新数组返回,如果length大于original的长度,那么多出来的部分系统自动赋予默认值(0/null);
2) type[] copyOfRange(type[] original, int from, int to); // 拷贝[from, to)区间,如果to超出original的长度,那么超出部分赋予0/null;
!!除此之外,如果填拷贝的量特别巨大,则应该考虑使用操作系统的memcpy系统调用了,毕竟系统调用的内存填充(复制)的效率是最最高的,Java的将该系统调用包装在System里(System本身就表示OS平台,OS的很多系统调用都在该类中有包装器),其静态方法arraycopy就是memscpy的包装:
static native void System.arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
!意思非常明确,就是将src从srcPos开始的length长度拷贝到dest从destPos开始的位置处,其参数跟memcpy是一致的;
5. 填充:
1) void fill(type[] a, type val); // 整个数组填充val
2) void fill(type[] a, int fromIndex, int toIndex, type val); // 区间填充
6. 连缀成字符串:String toString(type[] a); // 分别调用各个元素的toString,将各个结果连缀成一个完整的String返回,中间用", "(逗号+空格分隔);
!!如果数组元素是自定义类型就必须自己实现toString方法才行;
!!多线方法:都以parallel作为前缀,表示并行计算
7. 排序:
1) void parallelSort(type[] a);
2) void parallelSort(type[] a, int fromIndex, int toIndex);
8. 二元迭代:
1) void parallelPrefix(type[] a, int from, int to, typeBinaryOperator op);
i. 表示将数组a的[from, to)进行typeBinaryOperator的二元迭代;
ii. 其中BinaryOperator就是二元操作符的意思;
iii. 该方法的意思其实就是以下代码:
static void parallelPrefix(type[] a, int from, int to, TypeBinaryOperator op) {
for (int i = from; i < to; i++) {
type left = (i == 0)? 1: a[i - 1]; // 对于第一个元素left = 1
type right = a[i];
a[i] = left op right;
}
}
!即从头到尾逐个按照left op right的方式更新,那更新后的值继续迭代下一个元素
iv. 其中typeBinaryOperator表示二元运算法,type目前基本支持Java的基础类型(int、double等),该运算法其实是一个函数式接口,里面只有一个方法:
public interface TypeBinaryOperator {
type applyAsInt(type left, type right);
}
!!例如上面的如果想使用连乘迭代那就可以直接用Lambda表达式:Arrays.parallelPrefix(arr, 1, 5, (left, right) -> left * right);就行了;
2) 不指定区间的版本:void parallelPrefix(type[] a, typeBinaryOperator op); // 默认区间就是全部[0, length] == [0, length + 1);
!!如果是数组[1, 2, 3, 4, 5]进行全区间的连乘迭代,得到的结果就是[1, 2, 6, 24, 120];
9. 填充:
1) void parallelSetAll(type[] a, TypeUnaryOperator op);
2) 该方法就是用填充算法为数组a的每个元素赋值;
3) UnaryOperator是一元运算符的意思,之所以是一元是因为该方法默认用元素的索引来生成该元素的值,该接口也是一个函数式接口:
public interface TypeUnaryOperator {
type applyAsInt(type operand); // 利用索引生成一个值,如何生成自己定义
}
4) 该方法的意思就是:
static void parallelSetAll(Type[] a, TypeUnaryOperator op) {
for (int i = 0; i < a.length; i++) {
a[i] = op(i);
}
}
5) 例如:Arrays.parallelSetAll(a, index -> index * 5); // 一个长度为5的int数组其填充结果就是[0, 5, 10, 15, 20]