【C语言/数据结构】排序(直接插入排序|希尔排序)

🌈个人主页: 秦jh__https://blog.csdn.net/qinjh_?spm=1010.2135.3001.5343
🔥 系列专栏: 《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm=1001.2014.3001.5482

​​​​

目录

插入排序

直接插入排序:

希尔排序

预排序

gap的取值

时间复杂度

[​编辑 ​编辑](#编辑 编辑)

完整代码呈现


前言

💬 hello! 各位铁子们大家好哇。

今日更新了插入排序的内容

🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝

插入排序

直接插入排序:

下方是原理图:

cpp 复制代码
//时间复杂度:O(N^2) 逆序
//最好的情况:O(N)  顺序有序
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

分析:此过程为升序。end指向第一个要比较的元素的下标,tmp为待插入元素。当tmp小于前面的元素时,把前一位元素往后移,end--,使其指向前一位(更小的)元素。当tmp不再大于前一位元素,就直接用tmp替换。需注意:for循环的结束条件。

希尔排序

希尔排序有2步:

  1. 预排序(接近有序)(分别对每个分组进行插入排序)
  2. 直接插入排序

预排序

分析:我们假设每组的间隔是3,相同颜色相连的数字是同一组,红色原本是9,6,4,1,进行插入排序后就变成1,4,6,9。其他组别以此类推。这样的目的是使较大的数排后面,小的排前面,让他接近有序。最后再整体进行插入排序,这样可以提高效率。

预排序代码实现如下:

cpp 复制代码
	int gap = 3;

	//一组一组排
	//for (int j = 0; j < gap; j++)
	//{
	//	for (int i = j; i < n - gap; i += gap)
	//	{
	//		int end=i;
	//		int tmp = a[end + gap];
	//		while (end >= 0)
	//		{
	//			if (tmp < a[end])
	//			{
	//				a[end + gap] = a[end];
	//				end -= gap;
	//			}
	//			else
	//			{
	//				break;
	//			}
	//		}
	//		a[end + gap] = tmp;
	//	}
	//}

	//多组并排
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}

分析:预排序有两种写法,第二种写法比第一种少了一层循环。

我们先分析第一种:预排序是在我们前面讲的直接插入排序中修改的。内层for循环中,因为是间隔着排序,所以每次加减时都是加减gap,内层循环结束后,就完成了第一组的排序,外层for循环控制第几组排序。

第二种:少了外层的for循环,i就要从0开始,然后每次加1,这样就是混合着多组进行排序,其他步骤不变。

gap的取值

  • gap越大,大的值更快调到后面,小的值可以更快调到前面,越不接近有序。
  • gap越小,跳的越慢,但是越接近有序,如果gap==1,就是直接插入排序。
cpp 复制代码
//多组并排
int gap = n;
//gap>1时是预排序,目的是让他接近有序
//gap==1是直接插入排序,目的是让他有序
while (gap>1)
{
	//gap=gap/2;
	gap = gap / 3 + 1;
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = a[end + gap];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
}

分析:在实际中,gap取值看数量情况定。当gap>1,循环进行预排序,每次/2,最后一次肯定是1。但是每次/2,进行的预排序可能还是过多,就可以/3,不过要保证最后一次是1,因为当2除以3时==0,所以就要在后面加上1。具体除以几,主要保证最后一次是1即可。

时间复杂度

分析:最后一轮累计的挪动次数大约为:n 。总的平均时间复杂度是O(N^1.3),因为计算过程十分复杂,只需了解。

完整代码呈现

cpp 复制代码
//平均O(N^1.3)
void ShellSort(int* a, int n)
{
	//int gap = 3;

	//一组一组排
	//for (int j = 0; j < gap; j++)
	//{
	//	for (int i = j; i < n - gap; i += gap)
	//	{
	//		int end=i;
	//		int tmp = a[end + gap];
	//		while (end >= 0)
	//		{
	//			if (tmp < a[end])
	//			{
	//				a[end + gap] = a[end];
	//				end -= gap;
	//			}
	//			else
	//			{
	//				break;
	//			}
	//		}
	//		a[end + gap] = tmp;
	//	}
	//}

	//多组并排
	int gap = n;
	//gap>1时是预排序,目的是让他接近有序
	//gap==1是直接插入排序,目的是让他有序
	while (gap>1)
	{
		//gap=gap/2;
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}
相关推荐
古希腊掌管学习的神18 分钟前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca20 分钟前
洛谷 P1706 全排列问题 C语言
算法
古希腊掌管学习的神24 分钟前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
赵钰老师25 分钟前
【R语言遥感技术】“R+遥感”的水环境综合评价方法
开发语言·数据分析·r语言
浊酒南街25 分钟前
决策树(理论知识1)
算法·决策树·机器学习
就爱学编程33 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条38 分钟前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
Oneforlove_twoforjob1 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
每天都要学信号1 小时前
Python(第一天)
开发语言·python