希尔排序的思想及代码实现
希尔排序的基本思想
希尔排序简单点来说,就是直接插入排序的优化,能比直接插入排序应对更多的情况,但两者还是有些区别:
ps:如果有不清楚直接插入排序的兄弟可以这篇文章,里面有详细的介绍: juejin.cn/post/715497…
在我们排序时,假设我们想用直接插入排序来排,但是要排序的数组刚好是个逆序的,那它的时间复杂度就会比较大,也就是说执行的过程会更多更繁琐,而为了优化这种排序的过程,我们可以先对这种数组进行预排序,预排序就是先让这个数组进行粗略的排序,目的就是让数组更接近有序,而不是一个完全的逆序数组,这样直接插入排序在执行的时候,效率就会变高,这就是希尔排序的思想。
那么怎么进行预排序呢?我们可以把他们分成几个组,来进行排序,比如下面这个数组(假设最后的结果为升序):
我们可以先令gap等于3(后面会解释gap到底怎么取值),意思就是把该数组每3个空分一个组,如下图(end为数组的下标):
在我们分好组之后,接下来就可以开始预排序了,也就是一组一组的排序,排序方式跟直接插入排序一样:
如上图所示,排序从蓝色分组中的第一组的第二个数5开始,跟直接插入排序一样,将前面的9看作已经排好的数组,5小于9,因此9要往后移,注意移动的时候是以gap为单位移动的;
蓝色这第一组排完序后,
end++
,开始对绿色分组中的第一组开始排序,tmp
也变成的绿色这第一组中要插入的数据,完成这几步操作后数组的状态如下图所示:
如上图所示,此时排序从绿色分组中的第一组开始,因此
arr[end]
指向该分组中的第一个元素1,tmp指向的7为此时要插入的元素,重复直接插入排序的步骤,1和7排完序后,end++,tmp则变成紫色这一组中要插入的数据,如下图所示:
用直接插入排序的方法,重复以上操作。
直到这一步(如下图所示):
首先我们还是用直接插入排序的方式来排,5小于9,因此9要往后移,5要往前移到9原来的位置,然后end以gap为单位,向前移到8的位置,再让tmp和8进行比较,然后重复上述操作,因为原来end是指的8的位置,因此在这个基础上,end++,如下图所示:
由此可以发现,tmp此时已经越界了,end所在的位置刚好是n-gap-1,因此可以将该条件作为排序终止的条件,此时gap为3的排序就完成了。
这时的数组已经接近有序了,但希尔排序并不是只需要排这一轮,gap的值在每一轮排序终止后都会减少,因为gap的值每减少一次,数组就会更接近有序,当gap值为1时,此时的希尔排序就相当于直接插入排序了,那么究竟怎么控制gap的值呢?
//如何控制gap的值:
int gap = n;
while (gap > 1)
{
gap = gap / 2;
//用于控制gap的值
//此处省略排序的主体
}
如上述代码所示,我们可以用while来控制gap的值,gap的值在每一轮排序终止后,都会整除一次2,但是为什么是除2呢?
因为gap的值不管为多少,在整除n次2以后,最终的值都会变成1,满足直接插入排序的条件,比如当gap为5,整除2后会变成2,再整除2后就变成了1
希尔排序的代码实现
当我们了解上述希尔排序的主要思想后,就可以来写代码了,废话不多说,直接放代码:
#include<stdio.h> /*printf*/
void PrintArray(int* arr, int len) /*打印数组内容*/
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void ShellSort(int* arr, int n) /*希尔排序*/
{
int gap = n;
//gap:分组的依据,gap的值每减小一次,排序就会越接近有序
while (gap > 1)
//当gap的值为1时,排序就相当于直接插入排序
{
gap = gap / 2;
//控制gap的值,使其最终能够等于1,满足直接插入排序的条件
for (int i = 0; i < n - gap; i++)
//end排完序后的位置为n-gap-1,因此将n-gap作为终止条件
{
int end = i;
int tmp = arr[end + gap];
//将要插入的数据存到tmp当中
while (end >= 0)
{
if (arr[end] > tmp)
{
arr[end + gap] = arr[end];
//如果tmp的值较小,则arr[end]以gap为单位向后移动
end = end - gap;
//gap继续向前比较
}
else
{
break;
//排序完成后退出循环
}
}
arr[end + gap] = tmp;
//此时tmp后面的值都比它大,前面要么没有数据,要么都比它小
//tmp成功插入
}
}
PrintArray(arr, n); /*打印函数*/
}
int main()
{
int arr[] = { 9,1,2,5,7,4,8,6,3,5 };
int len = sizeof(arr) / sizeof(arr[0]);
//计算数组的长度
ShellSort(arr, len); /*希尔排序*/
return 0;
}
运行结果:
以上就是本篇文章的全部内容,如果你觉得对你多少有些帮助,可以点个赞或者收藏一波支持一下哦,欢迎各位大佬批评指正,咱们下次再见!