JDK 1.7源码阅读笔记(四)集合类之Arrays 源码分析
2018-03-02 17:32
543 查看
一、前言
(1)Arrays包含用来操作数组(比如排序和搜索)的各种方法。Arrays提供的方法都是静态方法,Arrays的构造函数是私有的,也就是不能被实例化。
(2)包含一个允许将数组作为列表来查看的静态工厂。
(3)除非特别注明,否则如果指定数组引用为 null,则此类中的方法都会抛出 NullPointerException。
(4)涉及的排序算法简单介绍
1> Java1.7之前的快排:在Java1.7之前的快排只是普通的快排,跟我们今天要研究的快排不一样,性能也差了许多,但其中对快排所做的各种优化我们依然是可以学习的。
Java1.7的快排:Java1.7的快排是一种双轴快排,顾名思义:双轴快排是基于两个轴来进行比较,跟普通的选择一个点来作为轴点的快排是有很大的区别的。算法是由Vladimir Yaroslavskiy在2009年研究出来的,并在2011年发布在了Java1.7。由于Arrays.sort对于数组的排序做了各种各样的优化,并且大多数优化和我们今天要研究的双轴排序无关,所以我们暂且略过,以后有时间研究Arrays源码的时候我们再进行分析。
2>TimSort是mergeSort的一种改进,引入binarySort进行子数组的排序,实现优化(原来的子数组排序是采用的选择排序),每次进行子数组合并的时候会进行一些特殊的处理来进行对一些特殊情况的优化。
TimSort算法是一种起源于归并排序和插入排序的混合排序算法,设计初衷是为了在真实世界中的各种数据中可以有较好的性能。该算法最初是由Tim Peters于2002年在Python语言中提出的。
TimSort 是一个归并排序做了大量优化的版本。对归并排序排在已经反向排好序的输入时表现O(n2)的特点做了特别优化。对已经正向排好序的输入减少回溯。对两种情况混合(一会升序,一会降序)的输入处理比较好。
在jdk1.7之后,Arrays类中的sort方法有一个分支判断,当LegacyMergeSort.userRequested为true的情况下,采用legacyMergeSort,否则采用ComparableTimSort。并且在legacyMergeSort的注释上标明了该方法会在以后的jdk版本中废弃,因此以后Arrays类中的sort方法将采用ComparableTimSort类中的sort方法。
注:
此类中所含方法的文档都包括对实现 的简短描述。应该将这些描述视为实现注意事项,而不应将它们视为规范 的一部分。实现者应该可以随意替代其他算法,只要遵循规范本身即可。(例如,sort(Object[]) 使用的算法不必是一个合并排序算法,但它必须是稳定的。)
二、源码
(1)Arrays包含用来操作数组(比如排序和搜索)的各种方法。Arrays提供的方法都是静态方法,Arrays的构造函数是私有的,也就是不能被实例化。
(2)包含一个允许将数组作为列表来查看的静态工厂。
(3)除非特别注明,否则如果指定数组引用为 null,则此类中的方法都会抛出 NullPointerException。
(4)涉及的排序算法简单介绍
1> Java1.7之前的快排:在Java1.7之前的快排只是普通的快排,跟我们今天要研究的快排不一样,性能也差了许多,但其中对快排所做的各种优化我们依然是可以学习的。
Java1.7的快排:Java1.7的快排是一种双轴快排,顾名思义:双轴快排是基于两个轴来进行比较,跟普通的选择一个点来作为轴点的快排是有很大的区别的。算法是由Vladimir Yaroslavskiy在2009年研究出来的,并在2011年发布在了Java1.7。由于Arrays.sort对于数组的排序做了各种各样的优化,并且大多数优化和我们今天要研究的双轴排序无关,所以我们暂且略过,以后有时间研究Arrays源码的时候我们再进行分析。
2>TimSort是mergeSort的一种改进,引入binarySort进行子数组的排序,实现优化(原来的子数组排序是采用的选择排序),每次进行子数组合并的时候会进行一些特殊的处理来进行对一些特殊情况的优化。
TimSort算法是一种起源于归并排序和插入排序的混合排序算法,设计初衷是为了在真实世界中的各种数据中可以有较好的性能。该算法最初是由Tim Peters于2002年在Python语言中提出的。
TimSort 是一个归并排序做了大量优化的版本。对归并排序排在已经反向排好序的输入时表现O(n2)的特点做了特别优化。对已经正向排好序的输入减少回溯。对两种情况混合(一会升序,一会降序)的输入处理比较好。
在jdk1.7之后,Arrays类中的sort方法有一个分支判断,当LegacyMergeSort.userRequested为true的情况下,采用legacyMergeSort,否则采用ComparableTimSort。并且在legacyMergeSort的注释上标明了该方法会在以后的jdk版本中废弃,因此以后Arrays类中的sort方法将采用ComparableTimSort类中的sort方法。
注:
此类中所含方法的文档都包括对实现 的简短描述。应该将这些描述视为实现注意事项,而不应将它们视为规范 的一部分。实现者应该可以随意替代其他算法,只要遵循规范本身即可。(例如,sort(Object[]) 使用的算法不必是一个合并排序算法,但它必须是稳定的。)
二、源码
public class Arrays {//类的构造函数是私有的 private Arrays() {} ........ //整数数组的排序,升序排列,如果需要降序,则自行处理 public static void sort(int[] a) { // JDK1.7的排序算法使用了DulaPivotQuickSort算法,该算法是快排的一种变种算法 DualPivotQuicksort.sort(a); } //基本类型的排序都使用该排序算法 public static void sort(double[] a) { DualPivotQuicksort.sort(a); } //对象的排序,对象必须是可比较的,即必须实现Compareable接口 public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a);//用合并排序算法,需要额外的一倍空间 else ComparableTimSort.sort(a);//用TimSort算法 } //合并排序算法的实现,需额外的dest空间 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--) //用Comparable的排序接口 swap(dest, j, j-1);//交换两个元素 return; } //元素长度大于7时,按合并排序算法进行排序 int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1; //从low到mid的元素进行合并排序 mergeSort(dest, src, low, mid, -off); //从mid到high的元素进行合并排序 mergeSort(dest, src, mid, high, -off); //如果两部分已经有序,则执行合并即可 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++]; } } //二分搜索算法,要求a是有序的 public static int binarySearch(long[] a, long key) { return binarySearch0(a, 0, a.length, key); } //执行二分搜索 private static int binarySearch0(long[] a, int fromIndex, int toIndex, long key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1;//用移位运算实现除法 long midVal = a[mid]; if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found. } //对象的二分搜索 private static int binarySearch0(Object[] a, int fromIndex, int toIndex, Object key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1; Comparable midVal = (Comparable)a[mid]; int cmp = midVal.compareTo(key);//用Compareable的排序接口 if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found. } //数组的比较算法 public static boolean equals(byte[] a, byte[] a2) { if (a==a2)//指向同一个值 return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length)//数组长度的比较 return false; for (int i=0; i<length; i++) if (a[i] != a2[i])//值的比较 return false; return true; } //填充算法,Java没有类似C的memset,不然效率更高 public static void fill(char[] a, char val) { for (int i = 0, len = a.length; i < len; i++) a[i] = val; } //计算Hash值的算法 public static int hashCode(byte a[]) { if (a == null) return 0; int result = 1; for (byte element : a) result = 31 * result + element;//使用了Time31的Hash算法 return result; }
相关文章推荐
- JDK 1.7源码阅读笔记(七)集合类之HashMap
- JDK 1.7源码阅读笔记(六)集合类之AbstractCollection
- JDK 1.7源码阅读笔记(二)集合类之ArrayList
- JDK 1.7源码阅读笔记(三)集合类之LinkedList
- JDK 1.7源码阅读笔记(五)集合类之Collection
- jdk源码阅读笔记(1.9版)非concurrent包的集合
- JDK 1.7源码阅读笔记(一)String,StringBuilder,StringBuffer
- java集合HashMap源码分析(JDK1.7)
- nginx 源码分析阅读笔记-进程管理
- 【集合框架】JDK1.8源码分析之LinkedHashMap(二)
- JAVA 集合类(java.util)源码阅读笔记------Vector
- 【集合框架】JDK1.8源码分析之HashMap & LinkedHashMap迭代器(三)
- ReentrantLock的JDK源码阅读笔记
- 【集合框架】JDK1.8源码分析之LinkedList(七)
- 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
- JDK源码(1.7) -- java.util.Arrays
- JDK源码阅读之Collection分析
- JDK源码阅读之Collection集合接口
- JDK源码阅读——HashMap(1.7)
- 【JDK1.8】JDK1.8集合源码阅读——TreeMap(一)