1.Arrays.sort()
Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,非常的好用。
1、Arrays.sort(int[] a)
这种形式是对一个数组的所有元素进行排序,并且是按从小到大的顺序。
sort()源码
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
//点开legacyMergeSort 有一个数组的(浅)拷贝,然后就是归并排序
private static void legacyMergeSort(Object[] a) {
Object[] aux = a.clone();
mergeSort(aux, a, 0, a.length, 0);
}
// 点开mergeSort
// src 源数组
// dest 目标数组
// low 开始下标
// high 尾端下标
// off 偏移量 对数组指定位置进行排序需要用到这个。
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
// 数组区间的数据长度
int length = high - low;
// 这里是对归并排序的一个优化,因为在对于少量数据的数组使用插入排序的效率更高。
// 所以这里加了一个插入排序的阈值为7
if (length < INSERTIONSORT_THRESHOLD) {
// 这里实现的是插入排序。将数组分为两个区间,其中一个为已排序区间,开始只有一个就是数组的
// 第一个元素,其余的都为未排序区间,将未排序区间的每一个元素与已排序区间做比较,找到合适
// 的位置插入
for (int i=low; i<high; i++)
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
// >>>1 表示做无符号位右移1 位 ,即除以2 .
int mid = (low + high) >>> 1;
// 这里进行递归排序,将 dest 数组的一半排序成 src数组
mergeSort(dest, src, low, mid, -off);
mergeSort(dest, src, mid, high, -off);
// 这里是对归并排序的第二个优化部分。
// 即进行归并排序的两部分分别排序后
// 前半部分的最大值 小于 后半部分的最小值,即已经是有序数组,就直接将 排序后的src 数组
// 复制 到dest 数组
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// 在这里将分别排序后的两个数组进行合并
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
// 前半部分值小
if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
dest[i] = src[p++];
// 后半部分值小
else
dest[i] = src[q++];
}
}
归并排序的时间复杂度为O(nlogn).
归并排序的空间复杂度为O(n),从代码中可以看出,归并排序会复制一个原数组,多开辟出来一块内存空间。
2、Arrays.sort(int[] a, int fromIndex, int toIndex)
这种形式是对数组部分排序,也就是对数组a的下标从fromIndex到toIndex-1的元素排序,注意:下标为toIndex的元素不参与排序
降序
3.利用Collections.reverseOrder()方法:
Integer[] a = {1,2,3,4,5,6,7,8,9};
Arrays.sort(a,Collections.reverseOrder());
for(int arr:a) {
System.out.print(arr + " ");
}
//点开reverseOrder
public static <T> Comparator<T> reverseOrder() {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
}
//继续看ReverseComparator
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
@java.io.Serial
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER
= new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
//Comparable是个接口,重写compareTo()方法
public interface Comparable<T> {
public int compareTo(T o);
}
4.实现Comparator接口的复写compare()方法:
public static void main(String[] args) {
Integer[] a = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5};
//定义一个自定义类MyComparator的对象
Comparator cmp = new MyComparator();
Arrays.sort(a,cmp);
for(int arr:a) {
System.out.print(arr + " ");
}
}
//实现Comparator接口
class MyComparator implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
/*如果o1小于o2,我们就返回正值,如果o1大于o2我们就返回负值,
这样颠倒一下,就可以实现降序排序了,反之即可自定义升序排序了*/
//return o2.compareTo(o1);
return o2-o1;
}
}
compareTo()的返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的 差值,如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方 全比较完,这时就比较字符的长度.
String s1 = "abc";
String s2 = "abcd";
String s3 = "abcdfg";
String s4 = "1bcdfg";
String s5 = "cdfg";
System.out.println( s1.compareTo(s2) ); // -1 (前面相等,s1长度小1)
System.out.println( s1.compareTo(s3) ); // -3 (前面相等,s1长度小3)
System.out.println( s1.compareTo(s4) ); // 48 ("a"的ASCII码是97,"1"的的ASCII码是49,所以返回48)
System.out.println( s1.compareTo(s5) ); // -2 ("a"的ASCII码是97,"c"的ASCII码是99,所以返回-2)
看compareTo的源码
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
继续看compare的源码
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
其实就是如果返回1,就是升序,-1则是降序。