插入排序的基本思想在于每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中,直到全部记录插入完成。插入排序可以引申出三个排序算法:直接插入排序,折半插入排序,希尔排序。这里先介绍直接插入排序。
假设在排序过程中,带排序表L[1…n]在某次排序过程中的某一时刻状态如下:
{ 有序列表L[1…i-1] | L(i) | 无序列表L[i+1…n] }
为了将元素L(i)插入到已有序列的子序列L[1…i-1]中,我们需要执行以下操作(“L[ ]”表示一个表,“L()”表示一个元素):
1)查找出L(i)在L[1…i-1]中的插入位置k。
2)将L[k…i-1]中所有元素全部后移一个位置。
3)将L(i)复制到L(k)。
为了实现对L[1…n]的排序,可以将L(2)…L(n)一次插入到前面已经排好序的子序列中,初始假定L[1]是一个已排好的序列,上述操作只需执行n-1次就能得到一个有序的表。
public class InsertSort {
public static void main(String[] args) {
int[] arr = new int[] { 800, 9, 3, 6, 12, 54, 35, 411, 3, 245, 1, 0, 4 };
InsertSort.insert(arr);
}
public static int[] insert(int[] arr) {
int i, j;
int insertNote;// 要插入的数据
int[] array = arr;
// 从数组的第二个元素开始循环将数组中的元素插入
for (i = 1; i < array.length; i++) {
// 设置数组中的第2个元素为第一次循环要播讲的数据
insertNote = array[i];
j = i - 1;
while (j >= 0 && insertNote < array[j]) {
// 如果要播讲的元素小于第j个元素,就将第j个元素向后移动
array[j + 1] = array[j];
j--;
}
// 直到要插入的元素不小于第j个元素,将insertNote插入到数组中
array[j + 1] = insertNote;
}
return array;
}
}
直接插入排序算法的性能分析:
1)空间效率:仅使用了常数个辅助单元,所以空间复杂度为O(1)。
2)时间效率:在排序过程中,向有序子表中逐个插入元素的操作进行了n-1趟。每趟都分为比较关键字和移动元素。在最好的情况下,表中元素有序,每次插入元素只需比较一次二不需移动元素,因而时间复杂度为O(n)。最坏的情况下,表中元素逆序,比较次数最大(1+2+…+n-1),移动次数也最大(1+2+…+n-1)。平均情况下,=取最好和最坏的情况的平均值作为平均情况下的时间复杂度,总的比较次数和总的移动次数都约为n²/4。因此直接插入排序的时间复杂度为O(n²)。
3)稳定性:由于每次排序都是从后向前先比较再移动,所以不会出现相同元素相对位置发生变化的情况,所以直接插入排序是稳定的排序。