JDK 源码分析:插入排序算法

Posted 程序大咖秀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK 源码分析:插入排序算法相关的知识,希望对你有一定的参考价值。

插入排序介绍

        插入排序就是每次把待排序的数据一个一个插入到已经排好序的正确位置。就好比,你左手拿着扑克牌,用右手去取牌的时候,把取到的牌放到左手正确的位置。

插入排序示意图


基本思想:每次选取一个元素,然后选择合适的位置并将其插入,直到全部
元素插入完毕,数组呈有序状态。


算法分析

        下面,小咖将对 JAVA JDK1.8 源码中的插入排序算进行分析(详见java.util.DualPivotQuicksort类)。

通常,插入算法呈现出二次排序算法中的最佳性能,对于具有较少的元素来说,二次算法十分有效。

  • 适用于少量数据排序,是稳定的排序算法,其空间复杂度为 O(1),时间复杂度为 O(n2)。

JDK1.8 源码定义了使用插入排序算法的阈值:INSERTION_SORT_THRESHOLD,只有当待排序元素低于阈值时,使用插入排序;若超过,则使用其他排序算法。

1/**
2 * If the length of an array to be sorted is less than this
3 * constant, insertion sort is used in preference to Quicksort.
4 */

5private static final int INSERTION_SORT_THRESHOLD = 47;

约定变量

1int[] a;                                     // 待排序数组
2int left = 0;                             // 左端下标位置
3int right = a.length - 1;       // 右端下标位置

传统插入排序

对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。

 1/**
2 * Traditional (without sentinel) insertion sort,
3 * optimized for server VM, is used in case of
4 * the leftmost part.
5 */

6for (int i = left, j = i; i < right; j = ++i) {
7    // 按数组下标顺序,选取一个元素 ai
8    int ai = a[i + 1];
9
10    /**
11     * 往前搜寻,此过程中将大于 ai 的元素往后移动一个
12     * 位置,直到找到合适的位置,并将 ai 插入。
13     */

14    while (ai < a[j]) {
15        a[j + 1] = a[j];
16        if (j-- == left) {
17            break;        // find
18        }
19    }
20    a[j + 1] = ai;        // insert
21}

双插入排序

此方法称作 pair insertion sort,每次可以插入一对元素,首先插入第一个元素,然后将其当做哨兵再插入第二个元素,可以有效的减少查询范围。

 1// 跳过数组中升序的部分(连续)
2do {
3    if (left >= right) {
4        return;
5    }
6} while (a[++left] >= a[left - 1]);
7
8/**
9 * Every element from adjoining part plays the role
10 * of sentinel, therefore this allows us to avoid the
11 * left range check on each iteration. Moreover, we use
12 * the more optimized algorithm, so called pair insertion
13 * sort, which is faster (in the context of Quicksort)
14 * than traditional implementation of insertion sort.
15 */

16for (int k = left; ++left <= right; k = ++left) {
17    // 选取两个值分别为 a1、a2
18    int a1 = a[k], a2 = a[left];
19
20    // 使得 a1 始终大于 a2
21    if (a1 < a2) {
22        a2 = a1; a1 = a[left];
23    }
24
25    /**
26     * 对较大元素 a1 进行插入
27     * 方法:向前搜寻到合适位置,此过程中将所有大于 a1 的元素
28     * 往后摞 2 个位置(给 a2 的预留位置)并将 a1 插入。
29     */

30    while (a1 < a[--k]) {
31        a[k + 2] = a[k];
32    }
33    a[++k + 1] = a1;
34
35    /**
36     * 对较小元素 a2 进行插入
37     * 方法:由于 a1 > a2,故 a2 定在 a1 之前。利用上步中的 a1
38     * 作为哨兵,从a1 位置开始往前搜寻到合适位置,此过程中将
39     * 所有大于 a2 的元素往后摞 1 个位置,并将 a2 插入。
40     */

41    while (a2 < a[--k]) {
42        a[k + 1] = a[k];
43    }
44    a[k + 1] = a2;
45}
46
47// 对于数组为奇数的情况,将最后一个元素进行插入操作
48int last = a[right];
49while (last < a[--right]) {
50    a[right + 1] = a[right];
51}
52a[right + 1] = last;


以上是关于JDK 源码分析:插入排序算法的主要内容,如果未能解决你的问题,请参考以下文章

jdk8源码legacyMergeSort算法=插入排序+分治思想+归并优化,其实就这么简单

jdk8源码legacyMergeSort算法=插入排序+分治思想+归并优化,其实就这么简单

JDK源码——Arrays.sort()的实现

JDK 源码分析:快速排序算法

jdk8源码Arrays.sort插入排序,居然还可以成对插入

jdk8源码Arrays.sort插入排序,居然还可以成对插入