参考B站视频https://www.bilibili.com/read/cv3285768
CSDN大佬博客 https://blog.csdn.net/morewindows/category_859207.html
个人理解插入排序的思想类似于扑克牌摸牌,插牌(比较大小,定位),摸牌(取数):每一步将一个待排序的对象,按照其关键字的大小,插入到前面排好顺序的适当位置,直到对象全部插入为止。所以其基本需要俩个操作,定位置 ,插入。
插入排序通过定位的方法不同分为下面几种排序:
- 顺序法定位插入位置-->直接插入排序
- 二分法定位插入位置-->二分法插入排序
- 缩小增量多遍插入排序-->希尔排序
直接插入排序:
设初始数组为a[0...n-1];
- 初始时,将a[0]设置为有序,无序的为a[1]-->a[n-1],令i = 1, 插入其中,i++
- 插入a[i]前,数组a的前半段a[0]--a[i-1]是有序段,后半段a[i]--a[n-1]是无序段
- 插入a[i]使得a[0]--a[i-1]有序,也就是需要为a[i]找到有序位置j (o<= j <=i),将a[i]插入在a[j]的位置上。
如何插入--将前面定位位置j后面的元素到a[i]的元素后移一位,留出空位,让其插入
代码如下:
void sortInsert(int a[], int n){
int i, j, tmp;
for(i=1; i<n; i++){//从a[1]开始取数插入前面a[0...i-1]的有序序列中,
tmp = a[i];//使用一个变量暂存需要插入的数,
/* 定的位置为j,从i-1开始往前寻找,如果有比取的数大的元素就让其后移
* 如果到头了--j==0,或者找到比a[i]小的数,就可以插入到比a[i]小的元素的后面
* 或者开头a[0]
*/
for(j=i-1; j>=0 && tmp<a[j]; j--){
a[j+1] = a[j];
}
a[j+1] = tmp;
}
}
可以看出最好的情况是顺序有序,即全部都从小到大都排好了,但是需要比较次数n-1,但移动次数0
最坏的情况是逆序有序,即从大到小排,需要比较次数(n+2)(n-1)/2; 移动次数(n+4)(n-1)/2
平均情况, 比较次数(n+2)(n-1)/4 ;移动次数(n+6)(n-1)/4
结论:
直接插入排序是稳定的排序,而且不需要占用额外空间,所以空间复杂度为o(1)
原始数据越接近有序,排序越快
最坏情况下(输入数据是逆序的) T(n)=O(n^2)
平均情况下,耗时差不多为最坏情况的一半 O(n^2)
若想提高查找速度,需:
1. 减少元素的比较次数
2. 减少元素的移动次数