在学习《Thinking in java》集合一章时,快到末尾时讲解了排序和搜索中用到了sort()
,点进去看了下源码,发现第一遍看起来还有点不甚了解,遂专开一篇来学习理解。
一、sort(byte[] a, int left, int right)
示例:
上述代码中b
初始化一个byte
类型的数组,初始化时由于没有赋值,默认是0。随后调用了r.nextBytes(b)
对b
进行了赋值。紧接着直接Arrays.sort(b)
排序成功。那么sort()
是如何实现的呢?看下源码:
Arrays.class
Byte.class
DualPivotQuicksort.class
Arrays.class
里面的sort(byte[] a)
直接调用了DualPivotQuicksort.sort(a, 0, a.length - 1)
,把传进来的byte
类型的数组以及该数组最大下标传递进去。
接下来着重分析static void sort(byte[] a, int left, int right)
。老实说,一开始真没看懂这是啥玩意。网上百度了下,原来sort(byte[] a)
里使用了计数排序和插入排序两种方法,当大于29时,便是计数排序否则用插入排序。计数排序可以看我这篇博客:https://lizhongzhen11.github.io/2018/03/30/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F/ 。
学习完计数排序后再反过来看该方法,可能还不是立即能看懂的,这时候不妨将内部代码抽出来运行下。下面是我抽出来运行的部分代码:
|
|
- 首先是
for (int i = left - 1; ++i <= right; count[a[i] - Byte.MIN_VALUE]++);
这个for循环没看懂有什么用。我抽出来手动运行了一遍,猜测它可能是计数排序中用来计算重复值个数的,因为count[i]
被改变了。根据实际打印输出,第二行输出的应该是改变后的count
的下标值,以第一个输出15为例,它应该是下标15,而且在打印中输出了2次,那么在第三行从第一个开始数起(其实是从下标0开始数起),正好到下标15位置对于了2,所以网上没骗我,的确是计数排序的思想。(注意:由于b
是通过r.nextBytes()
随机产生的,所以每次打印输出并不一样,可以用自己实际打印输出的数值进行对比验证。) - 接下来看看源码中的第三个for循环,通过打印输出,发现
s
应该是数组中相同值的个数,排好一个减去一个。123456789101112131415161718192021222324252627282930313233343536public class Test222 {static Random r = new Random();static void sort2(byte[] a, int left, int right) {// Use counting sort on large arraysif (right - left > 29) {int[] count = new int[256];for (int i = left - 1; ++i <= right; count[a[i] - (-128)]++);for(int i = 0; i < a.length; i++) {System.out.print(a[i] + 128 + ",");System.out.print("a[" + i + "] = " + a[i] + ";");}System.out.println();for(int i = 0; i < count.length; i++) {System.out.print(count[i]); // count[i] 对应 相同值在数组中的总数}System.out.println();for (int i = 256, k = right + 1; k > left; ) {System.out.print("count["+ --i + "] = " + count[--i] + ",");while (count[--i] == 0);byte value = (byte) (i + (-128));int s = count[i];System.out.print("value = " + value + ",");System.out.print("s = " + s + ";");System.out.println();do {a[--k] = value;} while (--s > 0); // 这里的s其实是用来判断是否有相同值的,如果有排好一个减去一个}}}public static void main(String[] args) {byte[] b = new byte[31];r.nextBytes(b);sort2(b, 0, 30);}}