目录
引言
一、直接插入排序的相关概念
1.1、基本概念
1.2、直接插入排序过程详解
二、代码实现
三、时间复杂度
四、希尔排序
4.1、希尔排序的陈述
4.2、代码实现
4.3、时间复杂度
结语
引言
在计算机科学的世界里,排序算法是基础且重要的组成部分。它们是组织和处理数据的核心工具,能够让数据更易于检索、分析和理解。今天,我们将一同探讨一种简单而经典的排序算法——直接插入排序。 尤其对于初学者来说,理解直接插入排序的原理和实现,能够帮助你更好地掌握C语言的编程技巧,并为后续学习更复杂的排序算法奠定坚实的基础。本文将结合C语言代码实例,带你深入理解直接插入排序的原理、实现方法,并探讨其优缺点,让你能够轻松掌握这一基础算法。
一、直接插入排序的相关概念
1.1、基本概念
直接插入排序是插入排序的一种,其核心思想是:把待排序的序列,按其关键码值的大小逐个插入到一个已经排好序的有序序列中。
通过核心思想,我们了解到,直接插入排序的前提条件是有一个有序序列,那么,我们还没进行直接插入排序,难道就需要利用其他算法先排序一遍吗?当然不是,这里有个很隐晦的条件——单个元素也是有序序列!是不是感觉有点牵强,但是仔细想想,也确实是这样的。
1.2、直接插入排序过程详解
通俗点说,就是先找出一个有序序列(单个元素,一般用首元素),然后依次遍历后面的元素,然后在看看后面的元素适合放在哪个位置,就放在哪个位置
那么,具体的操作应该怎样呢?
首先,我们要创建两个变量,end 存放元素的下标,tmp存放的是下标对应的元素,而且,tmp 存放的元素是 arr[end+1] ,如图:
其次,判断 end 指向的元素 与 tmp 存放的元素比大小,如果比 tmp 大了,则 end 的元素覆盖 end+1的元素,如图:
直到 end 小于0为止。目前截止,这只是第一个循环,结束后,要将tmp的元素放到 arr[end+1] 中。
从第二循环开始, end 就等于 1 了,然后等于3 ,一直到倒数第二元素结束。
在上面的动图循环完成后,end 将会变成3 ,开始下一轮的操作。一直到倒数第二个元素为止,因为tmp始终比end大一 ,又不能让tmp越界访问。
二、代码实现
void InsertSort(int* arr, int n)
{assert(arr);for (int i = 0; i < n - 1; i++){int end = i;int tmp = arr[end + 1];while (end >= 0){if (arr[end] > tmp){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = tmp;}
}
代码这里正常写就行了,注意end的停止范围,不能让tmp越界访问哦!
三、时间复杂度
通过上面代码,可以看到有两个循环,而且结合过程,就知道它把序列遍历了两遍,所以时间复杂度为 O(N^2) ,当然,最好的情况就是序列本来就是有序或者近似有序的,则时间复杂度就变为O(N)。
四、希尔排序
前面提到,直接插入算法的时间复杂度为O(N^2) ,而只有在待排序列是有序的或者近似有序的时候,它的时间复杂度才能降为 O(N)。那么,有没有什么办法可以降低直接插入排序的时间复杂度呢?有的,那就是希尔排序
4.1、希尔排序的陈述
先选定一个整数,把带待排序文件所有记录分成各组,所有的距离相等的记录分在同一组内,并对每一组内的记录进行排序,然后 gap = gap/3 +1 得到下一个整数,再将序列分割成各组,进行插入排序。当 gap = 1时,就相当于直接插入排序
如图,是 gap = 3 时的分组
将每组排完序后:
gap = 3/3 +1 = 2, 所以就是这样分组的:
每组排好序后:
接下来的 gap = 2/3+1 = 1 ,也就是一个元素一组,相当于直接插入排序:
此刻再看,待排序序列已经成为一个近似有序序列,甚至是有序序列,这样,时间复杂度只有O(N)!
4.2、代码实现
void ShellSort(int* arr, int n)
{assert(arr);int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int tmp = arr[end + gap];while (end >= 0){if (arr[end] > tmp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = tmp;}}
}
这里要提一嘴,分组时的插入排序算法和直接插入排序算法是一样的,区别就在于,直接插入排序元素是一个挨着一个的,而分组元素中间有个 gap ,,把gap看成1就是直接插入排序了。因此,分组的排序只需要在直接排序算法的基础上把1改为gap就行了。
4.3、时间复杂度
有大佬说过希尔排序的时间复杂度非常复杂,但最后还是给出了具体的值:O(N^1.3)。鄙人水平有限,这里就不推导了。
可以看到,希尔排序的时间复杂度比直接插入排序的时间复杂度要小的很多,从某种意义上说,希尔排序即是一种新的排序,也是直接插入排序的延伸和改进!
结语
恭喜你,你已经掌握了C语言插入排序算法的核心知识! 通过本文的学习,你不仅理解了直接插入排序的原理,还学会了用C语言实现它,并了解了它的优缺点。 掌握直接插入排序,是成为一名合格程序员的必经之路。希望你能够将所学知识应用到实际项目中,不断提升自己的编程能力。 记住,实践是检验真理的唯一标准,多写代码,多思考,你就能在编程的世界里越走越远! 祝你在编程的道路上越走越好!