排序方式:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插⼊排序通常采用in-place在数组上实现,这种方法首先将第一个元素看做已排序区间,从未排序区间依次取出数据从已排序区间末端开始与已排序区间进行对比,将取出的元素插入到合适的位置。
例:对{6,4,9,8,3}数组进行排序
原始数据:6 4 9 8 3
第一次排序后:4 6 9 8 3
第二次排序后:4 6 9 8 3
第三次排序后:4 6 8 9 3
第四次排序后:3 4 6 8 9
排序完成......
时间复杂度:
最好情况下,即数组已经有序,此时只需要进行一次扫描,此时时间复杂度为:O(n);最坏情况下,即数组元素的排序方式与要求正好相反,此时每个数据都要重新插入,此时时间复杂度为:O(n^2)。
空间复杂度:
插⼊排序算法的运⾏并不需要额外的存储空间,是⼀个原地排序算法。空间复杂度为: O(1)。
稳定性:
在插⼊排序中,对于值相同的元素,我们可以选择将后⾯出现的元素,插⼊到前⾯出现元素的后⾯,这样就可以保持原有的前后顺序不变。所以是:稳定排序。
适用场景:
适用于大部分数据已经进行过排序或者已排序的数据库新增数据后进行排序的情况,插入排序会造成数据的大量偏移,因此建议在链表上使用。
代码:
第一种写法:
import java.util.Arrays;
/**
* 直接插入排序:
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* 稳定性:稳定
* */
public class InsertSort {
public static void main(String[] args){
int[] arr = {5,2,-6,8,-3,9,7,4,1,0,-5,3,6};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
MyInsertSort(arr);
System.out.println("MyInsertSort-排序后:");
System.out.println(Arrays.toString(arr));
}
public static void MyInsertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int tmp = arr[i];
int j = i-1;
for (; j >=0; j--) {
if(tmp <arr[j]){
arr[j+1] = arr[j];
}else{
break;
}
}
arr[j+1] = tmp;
}
}
}
第二种写法:
public static void MyInsertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int tmp = arr[i];
int j = i-1;
while(j>=0 && tmp<arr[j]){
arr[j+1] = arr[j];
j--;
}
arr[j+1] = tmp;
}
}
结果展示:
改进:(折半(二分)插入排序和希尔(Shell)排序)
折半(二分)插入排序法(Binary Insertion Sort)是直接插入排序法的改进,将它的算法和代码以及与直接插入排序的区别单独整理了出来,链接附上:
排序——插入排序的优化:折半(二分)插入排序
希尔排序也是简单插⼊排序的改进版,排序算法类似于简单插入排序,将数据区分成特定间隔的几个小分块,以插入排序法排完区块内的数据后再逐渐减少间隔的距离。但,可以减少数据搬移的次数,连接附上:
排序——希尔(Shell)排序及其与直接插入排序的对比