八大排序之直接插入排序
什么是直接插入排序?
直接插入排序是一种比较排序。
在生活中也经常用到这种排序。
比如在各类扑克游戏中,
整理手牌的过程就是一种直接插入排序的体现。
直接插入排序原理
- 通过构建有序序列,将新的数据插入到已经有序的数据当中去。
- 首先将序列中搞得第一个元素看做是已经有序的序列。
- 取出下一个元素,与已经有序序列中从最后一个数据向前逐次进行比较,如果有序序列中的元素大于该元素,将这个元素(有序序列)向后移位一格。
- 重复步骤3,直到找到已排序序列中的某个元素小于等于该元素时,将其插入到该元素后一个位置。
- 重复3,4,直到整个数组有序。
图解:
用{11,7,9,13,22,5,2,17}来举例理解:
第一趟排序 将第一个元素 11 看做是有序的序列,7作为下一个元素小于11,所以11向后移位,7填入11前的空位。
第二趟,{7,11}已经是排序过的有序数组了,9作为下一个元素小于11,故11再向后移位,空出自己的位置。之后9与7作比较,元素9大于元素7,9小于已排序序列中的元素,将其填入该元素后,填入11后移之后的留下的空位。
第三趟,{7,9,11}作为有序数组,下一个元素13大于11,位置不变。
第四趟,同理,元素22大于有序数组中最大的值13,位置不变。
第五趟,{7,9,11,13,22}为有序序列,5小于22,22后移。5小于13,13后移。5小于11,11后移。5小于9,9后移。5小于7,7后移。5填入7的位置。
第六趟,{5,7,9,11,13,22}有序序列,同理2移动到5的位置,5,7,9,11,13,22依次后移一位。
第七趟,{2,5,7,9,11,13,22}有序序列,17小于22,22后移,17大于13,填入13后的空位。排序完成。
算法复杂度
- 直接插入排序在排列接近有序的数组时,时间复杂度可以达到O(N),比较次数大概为n-1次,移动数据次数也为n-1。
- 但直接插入排序如果遇到接近逆序的数组时,时间复杂度为O(NN),此时比较次数约为n(n-1)/2,移动次数也接近n*n/2。
- 所以,直接插入排序算法的复杂度是O(N^2)。是复杂度较高的排序算法。
代码实现
拿第一趟排序分析:
首先定义end为有序序列中最后一个元素,通过外层for循环的循环变量i来控制end,7要被替换为11,所以事先保存该元素(未排序序列中的第一个元素)定义x来保存该元素。替换后end–,扫描(有序序列中)end的前一个元素,当end扫描到有序序列中第一个元素时,end–为-1,此时在循环跳出,将保存的x赋值给end+1处。
代码如下:
void InsertSort(int* a, int n)
{
assert(a);
for (int i = 0; i < n - 1; i++)
{
int end = i; // 使用i来控制end
int x = a[end + 1]; // 提前保存要替换掉的元素
while (end >= 0) // 当end-- 减到-1时跳出循环
{
if (a[end] > x)
{
a[end + 1] = a[end];
--end;
}
else
{
break; // 如果该元素大于end,则证明不需要移动,直接跳出循环。
}
a[end + 1] = x;
}
}
}