【C语言】插入排序---直接插入排序和希尔排序

一.直接插入排序

:把待排序的记录按其关键码值的大小逐个插入到一个已经排好的有序序列中,直到所有的记录插完为止,得到一个新的有序排列。
如,按顺序插入牌:


下述举例 是外来数字插入一个数组内

    //以arr数组为例
	int arr[] = { 3, 4, 5};
   //插入一个数字 tmp = 3
   //arr[2]>tmp 即arr[2+1]=arr[2]
   //arr[1]>tmp 即arr[1+1]=arr[1]
   //arr[0]<=tmp 即 arr[0+1]=tmp
    int arr[] = { 3, 3, 4, 5};

内部怎么排序呢?

           int end ;  //可移动的下标,从第一个数开始
		   int tmp ; //将插入数组的值
		   // tmp之前的数都是有序的,找tmp应该放的位置
		   //tmp与tmp之前的数比较
		   while (end >= 0)
		   {
			   if (arr[end] > tmp)
			   {
				   arr[end + 1] = arr[end];
				   end--;
			   }
			   else
			   {
				   break;
			   }
		   }         

思路:
1.int arr[] = { 3, 5, 4, 6, 5, 8, 9, 4 }假设3是已经排列好的数
2.找 arr[1] 应该放的位置
3.找 arr[2] 应该放的位置
4. 依次上述方法…
5. arr[7] 放到正确的位置后排序即可完成
代码演示

    //以arr数组为例
	int arr[] = { 3, 5, 4, 6, 5, 8, 9, 4 };
	// i之前的数都是有序的
	for (int i = 1; i < sizeof(arr) / sizeof(int) ; i++)
	{
	       int end = i-1;  //可移动的下标,从第一个数开始
		   int tmp = arr[i]; //tmp的值
		   // tmp之前的数都是有序的,找tmp应该放的位置
		   while (end >= 0)
		   {
		       //tmp与arr[end]比较
			   if (arr[end] > tmp)
			   {
				   arr[end + 1] = arr[end];
				   end--;
			   }
			   else
			   {
				   break;
			   }
		   }
		   //插入tmp
		   arr[end + 1] = tmp;
    }
	//遍历
	for (int j = 0; j < (sizeof(arr) / sizeof(int)); j++)
	{
		printf("%d ", arr[j]);
	}
	printf("\n");

二.希尔排序

:希尔排序是对直接插入排序的优化,是基于直接插入排序的排序方法,但效率又远远高于直接插入排序。
时间复杂度:o( n*1.3 )

分为两个理论:
1.预排列 ( 为了接近排列顺序 )
2.直接插入排列( 完成排列 )

预排列也就是分组排列
以 arr 数组为例的分组:

int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
//把该数组分为间隔为3的3组数
// arr[0]=9 arr[3]=6 arr[6]=3 为一组 直接插入排序为 arr[0]=3 arr[3]=6 arr[6]=9
// arr[1]=8 arr[4]=5 arr[7]=2 为一组 直接插入排序为 arr[1]=2 arr[4]=5 arr[7]=8 
// arr[2]=7 arr[5]=4 arr[8]1 为一组 直接插入排序为 arr[2]=1 arr[5]=4 arr[8]=7 
组合一起为 3 2 1 6 5 4 9 8 7 
    即 arr[] = { 3, 2, 1, 6, 5, 4, 9, 8, 7 }//排列后接近结果

上述代码演示:

int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int gap = 3;
//三组循环三次
for (int j = 0; j < gap; j++)
	{
	    //每组进行直接插入排序
		for (int i = gap+1; i < (sizeof(arr) / sizeof(int) - gap + 1); i += gap)
		{
			int end = i - gap;//可移动的下标
			int tmp = arr[i];
			//将tmp 插入正确的位置
			while (end >= 0)
			{
			    //tmp与arr[end]比较
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			//插入 tmp
			arr[end + gap] = tmp;
		}
	}

上述代码只是完成了一部分的排列,我们应该怎么把数组排列完成呢?
我们可以思考一下,希尔排列比直接插入排列多了一个变量 gap ,我们令 gap=1,希尔排序就变成了直接插入排序。现在我们需要再加一个 gap 不断变小的循环,让希尔排序渐渐地变成直接拆入排序。不要小看这个 gap ,gap 的存在使希尔排序的效率远远高于直接插入排序

完整代码演示

int main()
{
	int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
	//令 gap 为数组的个数
	int gap = sizeof(arr) / sizeof(int);
	while (gap > 1)
	{
	    //gap不断变小
		gap = gap / 3 + 1;//没严格要求gap怎么变小,但是,最后一次循环的gap一定要为1,最后一次要为直接插入排列
		for (int j = 0; j < gap; j++)
		{
			for (int i = gap + j; i < (sizeof(arr) / sizeof(int) - gap + 1); i += gap)
			{
				int end = i - gap;/可移动的指针
				int tmp = arr[i];
				//每组中的gap都要找到正确的位置
				while (end >= 0)
				{
				    //tmp与arr[end]比较
					if (arr[end] > tmp)
					{
						arr[end + gap] = arr[end];
						end -= gap;
					}
					else
					{
						break;
					}
				}
				//插入gap
				arr[end + gap] = tmp;
			}
		}
	}

	return 0;
}

下述代码是上述代码的优化,效率一样。反驳了一些同学用循环嵌套算时间复杂度的方法

int main()
{
	int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
	int gap = sizeof(arr) / sizeof(int);
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		//for (int j = 0; j < gap; j++)
		//{
		     // i=gap+i改为i=gap             i+=gap改为i++,同学们可以体会一下。(多组同时排序)
			for (int i = gap ; i < (sizeof(arr) / sizeof(int) - gap + 1); i ++)
			{
				int end = i - gap;
				int tmp = arr[i];
				while (end >= 0)
				{
					if (arr[end] > tmp)
					{
						arr[end + gap] = arr[end];
						end -= gap;
					}
					else
					{
						break;
					}
				}
				arr[end + gap] = tmp;
			}
		//}
	}

	return 0;
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值