经典排序算法之一 插入排序
插入排序,简单来说,就是将一组数据一个一个地插入到已经排好序的数组中,从而形成一个有序数组。完整的代码可以到我的 GitHub 上查看 Algorithm。
算法描述
- 对于数组 a[n] ,默认 a[0] 已经被排序,a[1] ~ a[n-1]无序。令 i = 0; j = i + 1。
- 取出 j 位置的值 a[ j ] ,在已排好的元素中,从后向前依次与 a[ j ] 比较,如果该元素 a[ j - 1] > a [ j ],则将 a[ j - 1] 移到 j 的位置,同时 j —。一次遍历结束后,可以向已排好的数组中插入一个元素,i ++。
- 重复步骤 2,直到 i = n -1。
算法图解
代码实现
1 | public static void insertSort(int[] arr){ |
效率分析
最好的情况是所有元素都已经由小到大排好了,比较次数为(n - 1)次,时间复杂度为 O(n);
最坏的情况,即所有元素都按降序排好了,比较次数为 1+2+3+..+ (n-1) = n(n-1)/2,移位次数为 比较次数 + (n-1) 次 ,时间复杂度为 O(n²)。
在我的机器上运行 10000 个元素排序,所用的时间为:
1 | 执行时间为:47ms |
20000 个元素所用的时间
1 | 执行时间为:180ms |
100000 个元素所用的时间
1 | 执行时间为:4261ms |
可见 插入排序 在数据越来越大时,执行时间也明显的变多。
二分法插入排序
上面的方法取出待排序的元素之后,从已排好的元素中,从后往前依次比较,这里可以使用二分查找的方法,找出该元素应该插入的位置 index,然后将 index 之后的元素统一向后移位。
1 |
|
二分查找最好情况是:每次查找的位置是已排数组元素的最后一个的下一个,此时无须进行向后移位操作,比较次数为 lgn。时间复杂度为 O(lgn)。
二分查找最坏情况是:每次查找的位置是已排数组元素的第一个位置,此时移位次数为:n(n-1)/2 + (n-1),比较次数仍为 lgn。时间复杂度为 O(n²)。
使用二分法插入排序,在我的机器上运行 10000 个元素排序,所用的时间为:
1 | 执行时间为:22ms |
20000 个元素所用的时间
1 | 执行时间为:56ms |
100000 个元素所用的时间
1 | 执行时间为:1255ms |
可以看出,二分法插入排序在效率上还是要高出不少。而且,直接插入排序与二分插入排序的空间复杂度都是 O(1)。
非常棒的资料
Title: 经典排序算法之一 插入排序
Author: mjd507
Date: 2017-01-21
Last Update: 2024-01-27
Blog Link: https://mjd507.github.io/2017/01/21/Algorithm-Insertion-Sort/
Copyright Declaration: This station is mainly used to sort out incomprehensible knowledge. I have not fully mastered most of the content. Please refer carefully.