插入排序实现的思路
对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
- 从第一个元素开始,该元素被认为已经被排序;
- 取出下一个元素,在已排序的元素序列中从后向前扫描;
- 如果已排序元素大于取出的元素,取出的元素就继续与前一个元素比较,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置;
- 重复步骤2~4。
Java实现插入排序
public class InsertionSort {
public static void insertionSort(int[] a){
int insertIndex;
int insertElement;
for(int i = 1;i < a.length;i ++){//外层循环,默认第一个元素已排序,从第二个元素开始,时间复杂度为O(N)
insertIndex = i - 1;//要排序元素开始比较的位置,默认为已排序元素的最后一位
insertElement = a[i];//要排序的元素,默认为外层循环的元素
while(insertIndex >= 0 && a[insertIndex] > insertElement){
//内层循环,当取出的元素小于或等于已排序的元素时继续,时间复杂度为O(N)
a[insertIndex + 1] = a[insertIndex];//将已排序的元素后移一位
insertIndex --;//要插入的位置前移一位
}
a[insertIndex + 1] = insertElement;//将要排序的元素插入到相应的位置上
}
}
//测试
public static void main(String[] args) {
int[] a = {5,10,64,3,4,1,6};
System.out.println("排序前:" );
for (int i : a) {
System.out.print(" " + i);
}
InsertionSort.insertionSort(a);
System.out.println();
System.out.println("排序后:" );
for (int i : a) {
System.out.print(" " + i);
}
}
}
测试结果:
总结
插入排序为两层循环嵌套,时间复杂度为O(N2),插入排序的while循环是先比较,移动待插入的位置,循环结束才真正交换数据位置。常用的for循环嵌套进行插入排序会导致每次插入一直和前面元素交换直到插入到待插入位置,上面的内循环用while寻找待插入位置,把其他元素后移的算法更合理,每次插入只一次进行一次交换。因插入排序每次只比较一位,对于逆序较多的数组效率较低,衍生算法希尔排序,会大幅加快逆序交换。
插入排序最好的情况是序列已经是升序排列了,在这种情况下,需要进行N-1次比较即可,此时时间复杂度为O(N),最坏的情况是降序排列,这时候时间复杂度为O(N2)。因此插入排序不适合对于数据量比较大的排序应用。但是如果需要排序的数据量很小(小于千),那么插入排序还是一个很不错的选择,插入排序平均时间复杂度为O(N2),但是他要比冒泡排序快一倍,比选择排序还要快一点,经常被用在较复杂的排序算法的最后阶段,例如快速排序。
算法是稳定的,假设a=b,且a在b的前面,其排序位置必然比b先确定,而后面再插入b时,必然在a的后面,所以是稳定的。
空间复杂度为O(1),不需要额外的空间。