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),这是高级排序算法也达不到的时间复杂度。显然,对于近乎有序的数组,大部分情况下都不需要移动元素。
当数组中存在相等元素时,插入排序中不会有操作 改变相等元素的相对位置,所以插入排序是稳定的。