ArrayList,排序方法的调用过程

// 排序方法
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
} public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
// 如果没有实现比较方法
if (c == null) {
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
if (Arrays.LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
} public static void sort(Object[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
//经查资料,这是个传统的归并排序,需要通过设置系统属性后,才能进行调用
// System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
if (Arrays.LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex);
else
ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
}

然后继续看下在没有实现Comparator接口的情况,传统归并排序的实现

private static void legacyMergeSort(Object[] a,
int fromIndex, int toIndex) {
// 复制对应范围的数组
Object[] aux = copyOfRange(a, fromIndex, toIndex);
mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
} // 使用插入排序进行优化的归并排序
// dest为要排序的数组
// off:负数,因为aux是复制a数组fromIndex-toIndex范围的数据,但位置从0开始,fromIndex-off则为aux开始的坐标
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
int length = high - low; // Insertion sort on smallest arrays
// 长度小于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;
int mid = (low + high) >>> 1; // 交换dest,src位置,这样就能排序src,然后合并到dest
// 注意这个递归的开始,dest为要排序的数组a,所以最终a会合并成有序的数组
mergeSort(dest, src, low, mid, -off);
mergeSort(dest, src, mid, high, -off); // If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
// 如果说src排完序后,两个范围的src,刚好前一个小于后一个,则直接复制。
// 例如两个范围【1,2】【3,4】,其实他们已经有序【1,2,3,4】
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
} // Merge sorted halves (now in src) into dest
// 可以看成两个有序的数组之间进行合并
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++];
}
} /**
* Swaps x[a] with x[b].
*/
private static void swap(Object[] x, int a, int b) {
Object t = x[a];
x[a] = x[b];
x[b] = t;
}

再看看当前默认使用的排序方法(没使用Comparable的情况)

/**
*
* @param a 待排序的数组
* @param lo 开始位置,包括当前位置
* @param hi 结束位置,不包括当前位置
* @param work
* @param workBase
* @param workLen
*/
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
assert a != null && lo >= 0 && lo <= hi && hi <= a.length; int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges
// 排序的范围小于32的情况
if (nRemaining < MIN_MERGE) {
// 从lo位置开始,返回最长的递增序列长度,(下面有介绍)
int initRunLen = countRunAndMakeAscending(a, lo, hi);
// 折半插入排序,(下面有介绍)
binarySort(a, lo, hi, lo + initRunLen);
return;
} /**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
int minRun = minRunLength(nRemaining);
do {
// Identify next run
int runLen = countRunAndMakeAscending(a, lo, hi); // If run is short, extend to min(minRun, nRemaining)
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
} // Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
ts.mergeCollapse(); // Advance to find next run
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0); // Merge all remaining runs to complete sort
assert lo == hi;
ts.mergeForceCollapse();
assert ts.stackSize == 1;
}

具体看看里面的方法实现

    /**
* 返回从lo开始最长递增序列
* @param a 待排序的数组
* @param lo 开始位置,包括当前位置
* @param hi 结束位置,不包含当前位置
* @return
*/
private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
assert lo < hi;
int runHi = lo + 1;
if (runHi == hi)
return 1; // Find end of run, and reverse range if descending
// 如果lo+1位置的数小于lo位置的数,就找出最长的递减序列,然后进行反转
if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
runHi++;
reverseRange(a, lo, runHi);
} else { // Ascending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
runHi++;
} // 返回递增的长度
return runHi - lo;
} // 反转
private static void reverseRange(Object[] a, int lo, int hi) {
hi--;
while (lo < hi) {
Object t = a[lo];
a[lo++] = a[hi];
a[hi--] = t;
}
} /**
* 折半插入排序
* @param a 待排序的数组
* @param lo 开始位置,包括当前位置
* @param hi 结束位置,不包含当前位置
* @param start start以前为递增序列
*/
private static void binarySort(Object[] a, int lo, int hi, int start) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
// 从start开始遍历
for ( ; start < hi; start++) {
Comparable pivot = (Comparable) a[start]; // Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
// 二分找lo到start(不包括start)范围内,找到pivot适合插入的位置
while (left < right) {
int mid = (left + right) >>> 1;
if (pivot.compareTo(a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right; /*
* The invariants still hold: pivot >= all in [lo, left) and
* pivot < all in [left, start), so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
// 如果只需后移2位或者1位,直接换值
// 更多,则调用系统方法进行复制
switch (n) {
case 2: a[left + 2] = a[left + 1];
case 1: a[left + 1] = a[left];
break;
default: System.arraycopy(a, left, a, left + 1, n);
}
// 后移成功后,赋值
a[left] = pivot;
}
}

没分析完。。。需要学习一波tim sort。。

ArrayList排序算法的源码的更多相关文章

  1. 三种排序算法python源码——冒泡排序、插入排序、选择排序

    最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...

  2. 6种基础排序算法java源码+图文解析[面试宝典]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结6大基础算法.java版强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步:1.思想2.图 ...

  3. 十大基础排序算法[java源码+动静双图解析+性能分析]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结十大基础排序算法.java版源码实现,强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步: ...

  4. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  5. SURF算法与源码分析、下

    上一篇文章 SURF算法与源码分析.上 中主要分析的是SURF特征点定位的算法原理与相关OpenCV中的源码分析,这篇文章接着上篇文章对已经定位到的SURF特征点进行特征描述.这一步至关重要,这是SU ...

  6. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

  7. GWO(灰狼优化)算法MATLAB源码逐行中文注解(转载)

    以优化SVM算法的参数c和g为例,对GWO算法MATLAB源码进行了逐行中文注解. tic % 计时器 %% 清空环境变量 close all clear clc format compact %% ...

  8. ArrayList总结及部分源码分析

    ArrayList源码阅读笔记 1. ArrayList继承的抽象类和实现的接口 ArrayList类实现的接口 List接口:里面定义了List集合的基本接口,ArrayList进行了实现 Rand ...

  9. ArrayList实现原理及源码分析之JDK8

    转载 ArrayList源码分析 一.ArrayList介绍 Java 集合框架主要包括两种类型的容器: 一种是集合(Collection),存储一个元素集合. 一种是图(Map),存储键/值对映射. ...

随机推荐

  1. Office Web Add-in的技术原理和开发常见问题剖析

    作者:陈希章 发表于 2017年12月20日 我过去发表过一些Office Add-in开发的文章,并且也在不同的场合分享过新的开发模式及其带来的机遇.有不少朋友给我反馈,也讨论到一些常见问题,我这里 ...

  2. Java读取excel表格

    Java读取excel表格 一般都是用poi技术去读取excel表格的,但是这个技术又是什么呢 什么是Apache POI? Apache POI是一种流行的API,它允许程序员使用Java程序创建, ...

  3. 【java】io流之字符输入流:java.io.Reader类及子类的子类java.io.FileReader

    package 文件操作; import java.io.File; import java.io.FileReader; import java.io.IOException; import jav ...

  4. puppet配置问题统计

    一. [root@client puppet]# puppetd --test --server master.test.cominfo: Creating a new SSL key for cli ...

  5. C:函数:功能:实现字符数组中所有字母的倒序存放并输出

    前两天小测碰到一道题,建立一个函数,功能:实现字符数组中所有字母的倒序存放并输出,一开始觉得简单跟数字数组差不多,运行一下发现很多格式错误,这些是不必要的错误,现在就来说下,先说一下代码思路:定义一个 ...

  6. 使用requests爬取猫眼电影TOP100榜单

    Requests是一个很方便的python网络编程库,用官方的话是"非转基因,可以安全食用".里面封装了很多的方法,避免了urllib/urllib2的繁琐. 这一节使用reque ...

  7. ArcGIS 网络分析[8.3] 设置IDENetworkDataset的属性及INetworkDataset的对比/创建网络数据集

    创建网络数据集就得有各种数据和参数,这篇文章很长,慎入. 网络分析依赖于网络数据集的质量,这句话就在这里得到了验证:复杂.精确定义. 本节目录如下: 1. INetworkDataset与IDENet ...

  8. bzoj 2298: [HAOI2011]problem a

    Description 一次考试共有n个人参加,第i个人说:"有ai个人分数比我高,bi个人分数比我低."问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n ...

  9. php-自动过滤、自动填充、自动验证

    最近又学到了一些新技巧,和大家分享下. 第一.当一个表单有很大内容时,我们在表单处理页面接收这些表单的值的时候就会重复 接收,于是就有了自动过滤的解决之法(核心就是把数据表里需要的字段接收) 首先:我 ...

  10. html5 canvas画布尺寸与显示尺寸

    我在用canvas制作画板时,遇到了绘图位置和鼠标位置不一致的问题,所以今天查阅了一下资料,解决了这个问题. canvas绘图原理 在Canvas元素的内部存在一个名为2d渲染环境(2d rederi ...