深入理解C语言:详解直接插入排序的实现与优化

目录

引言

一、直接插入排序的相关概念

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语言实现它,并了解了它的优缺点。 掌握直接插入排序,是成为一名合格程序员的必经之路。希望你能够将所学知识应用到实际项目中,不断提升自己的编程能力。 记住,实践是检验真理的唯一标准,多写代码,多思考,你就能在编程的世界里越走越远! 祝你在编程的道路上越走越好!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值