排序算法之插入排序
1. 介绍
有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然保持有序,这个时候就要用到一种新的排序方法——插入排序法。
插入排序的基本操作就是将一个数据插入到已经排好序的有序数列中,从而得到一个新的、个数加一的有序数列,算法适用于少量数据的排序,时间复杂度为O(n^2),是稳定的排序方法。
插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
其实插入排序非常类似于玩扑克牌。
在开始摸牌时,左手是空的,牌面朝下放在桌上。接着,一次从桌上摸起一张牌,并将它插入到左手一把牌中的正确位置上。为了找到这张牌的正确位置,要将它与手中已有的牌从右到左地进行比较。无论什么时候,左手中的牌都是排好序的。
2. 算法描述
插入排序的基本思想是:每步将一个待排序的纪录,按其值的大小插入到前面已经排序的数列中适当位置上,直到全部插入完为止。
上图表明了插入排序算法的过程,每轮排序后的结果:
3. 算法实现
package com.demo;
/**
* 插入排序算法
*
* @author 小明
*
*/
public class InsertionSort {
/**
* 插入排序(升序排序)
*
* @param array
* 待排序数组
*/
public static void sort(int[] array) {
for (int i = 1, len = array.length; i < len; i++) { // 外层循环遍历从第2个元素到最后一个元素
if (array[i - 1] > array[i]) { // 当前遍历到的元素比前一个元素小,则需要在已排序部分去查找插入位置
int tmp = array[i]; // 暂存当前元素值
int j = i; // 保存插入位置
// 循环,查找元素插入位置,在找到该位置前,每个元素依次后移一位
for (; j > 0 && array[j - 1] > tmp; j--) {
array[j] = array[j - 1];
}
array[j] = tmp; // 将元素插入找到的位置
}
System.out.println("第" + i + "轮排序结果:");
show(array);
}
}
/**
* 显示数组中各元素值
*
* @param array
* 待显示的数组
*/
private static void show(int[] array) {
for (int i : array) {
System.out.print(i + "\t");
}
System.out.println();
}
public static void main(String[] args) {
int[] array = { 6, 5, 3, 1, 8, 7, 2, 4 };
sort(array);
System.out.println("*******************");
System.out.println("排序后:");
show(array);
}
}
运行结果:
第1轮排序结果:
5 6 3 1 8 7 2 4
第2轮排序结果:
3 5 6 1 8 7 2 4
第3轮排序结果:
1 3 5 6 8 7 2 4
第4轮排序结果:
1 3 5 6 8 7 2 4
第5轮排序结果:
1 3 5 6 7 8 2 4
第6轮排序结果:
1 2 3 5 6 7 8 4
第7轮排序结果:
1 2 3 4 5 6 7 8
*******************
排序后:
1 2 3 4 5 6 7 8
将待插入记录array[i]的值暂存到临时变量tmp中,将tmp中的值从右向左依次与有序集中元素array[j](j=i - 1, i - 2, …., 1, 0)的值比较:
若array[j]的值大于tmp的值,则将array[j]后移一个位置。
若array[j]的值小于或等于tmp的值,则查找过程结束,j + 1即为tmp插入位置。值比tmp大的元素均已后移,所以j + 1的位置已经腾空,只要将tmp直接插入到此位置即可完成一趟插入排序。
若array[j]的值始终大于tmp的值,则最终将tmp的值插入到索引为0的位置。
4. 结束语
如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。
最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。
最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n*(n-1)/2次。插入排序的赋值操作是比较操作的次数加上 (n-1)次。
平均来说插入排序算法的时间复杂度为O(n^2)。因而,插入排序不适合对于数据量比较大的排序应用。