InsertionSort

1.动图演示

1. 动图1

双层循环,外部循环选择需要与数组中前面元素比较的元素。内层循环,从该选定元素开始 与 该元素左边的元素进行比较。
如果选定元素小于左边元素 则与之交换位置。直至找到正确的位置,此次内层循环后,左侧部分元素已经有序。

2.动图2

动图1的优化版本。每次比较的时候不再与前面的元素交换位置。如果选定元素 比 左边的小,则让左边元素覆盖相邻右边元素。这样减少了许多交换次数,提高了效率。

2.代码实现

//测试工具类在这里 https://www.cnblogs.com/paidaxing7090/p/15080493.html
import 测试工具类.SortTestHelper;

public class InsertionSort2{

    // 我们的算法类不允许产生任何实例
    private InsertionSort2(){}

    public static void sort(Comparable[] arr){

        int n = arr.length;
        for (int i = 0; i < n; i++) {

            // 寻找元素arr[i]合适的插入位置

            // 写法1
//            for( int j = i ; j > 0 ; j -- )
//                if( arr[j].compareTo( arr[j-1] ) < 0 )
//                    swap( arr, j , j-1 );
//                else
//                    break;

            //写法2比较精简与写法1 没差别 ,对应动图1
//            for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--)
//                swap(arr, j, j-1);

            //  写法3 对应动图2
            Comparable e = arr[i];
            int j = i;
            for( ; j > 0 && arr[j-1].compareTo(e) > 0 ; j--)
                arr[j] = arr[j-1];
            arr[j] = e;

        }
    }
    public static void sort(Comparable[] arr,int l,int r){
    	  
           for (int i = l; i <=r; i++) {

               // 寻找元素arr[i]合适的插入位置

               // 写法1 交换元素
//               for( int j = i ; j > 0 ; j -- )
//                   if( arr[j].compareTo( arr[j-1] ) < 0 )
//                       swap( arr, j , j-1 );
//                   else
//                       break;

               // 写法2比较精简与写法1 没差别 ,对应动图1
//               for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--)
//                   swap(arr, j, j-1);

               // 写法3 对应动图2
               Comparable e = arr[i];
               int j = i;
               for( ; j > l && arr[j-1].compareTo(e) > 0 ; j--)
                   arr[j] = arr[j-1];
               arr[j] = e;

           }
    }

    private static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }

    // 测试InsertionSort
    public static void main(String[] args) {
        int N0 = 20000;
        Integer[] arr0 = SortTestHelper.generateRandomArray(N0, 0, 100000);
        Integer[] arr = arr0.clone();
        SortTestHelper.testSort("sort.InsertionSort", arr0);
        SortTestHelper.testSort("sort.InsertionSort2", arr);
        int N2 = 40000;
        Integer[] arr2 = SortTestHelper.generateRandomArray(N2, 0, 100000);
        SortTestHelper.testSort("sort.InsertionSort2", arr2);
        return;
    }
}

3.测试结果

对于同样的数组,可以看到优化后的插入排序效率提升了。同时,优化后的时间复杂度还是在O(n^2)级别。

4.算法分析

4.1描述

插入排序(InsertionSort),一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增 1 的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。

4.2分析


插入排序的基本思路简***均时间复杂度为O(n^2)。但是如果所排序数组是近乎有序的,则它的时间复杂度为O(n),这是高级排序算法也达不到的时间复杂度。显然,对于近乎有序的数组,大部分情况下都不需要移动元素。
当数组中存在相等元素时,插入排序中不会有操作 改变相等元素的相对位置,所以插入排序是稳定的。