希尔排序
希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序,因D.L.Shell于1959年提出而得名
之前我们已经讲过直接插入排序
直接插入排序:https://blog.csdn.net/wfea_lff/article/details/104002438
这里就不多说了,直接进入主题
时间复杂度: O(n^1.3 ~ n^1.5)
空间复杂度 : O(1)
稳定性: 不稳定
希尔排序最关键的地方就在于分组,他就是因为分组的合理,使得算法的优化
排序过程如图所示:
从图中我们不难看出
相当于对直接插入排序的优化
1、先对数据进行分组,然后在同一组内使用直接插入将数据排序,其目的就是使得整个数据趋于有序
每次分组排序,从分好的第一组的第二个数据开始,按直接插入排序使得
第一组的前两个数据有序,
第二组的前两个数据有序,
。。。
第一组的前三个数据有序
。。。
2、分组的个数依次减少,做相同的事情 --》 第一次 5组 第二次 3组 第三次 1组
分组的序列: 序列中的任何两个元素都是互质的, 并且最后一个分组必须为1
分组的目的
使得待排序数字集变得较为有序,对于直接插入排序而言,数据越有序,其时间复杂度将越趋于O(n)
我这里用个例子来详细说明
例如:5,4,6,9,2,8,7
第一次排序
我们先将整个待排序的数字集先分组,我们首先分三组
第一组【5,9,7】
第二组【4,2】
第三组【6,8】
注意:这里只是我们算法思想上分的,不是真的用三个数组来分出来
我们不难看出分组的规律,第一个数字和第四个数字和第七个数字,即就是该数字的序号+3(这里我是+3处理的,可根据情况自己定,这里只是举例)
定义i为第一组第二个数字9的下标,让其与同组的前一个数字5相比较,和直接插入排序相同,如果比前一个数字大则i++,变成了第二组第二个数字2,在与该组的前一个数字4比较,比前一个数字小,则将该组第一个数字4,放到2的位置,把2放到4的位置;这个时候因为该组2之前已经没有数字了,所以继续i++,变成了第三组的第二个数字8,继续上述的操作,就完成了第一次排序
排序结果:5,2,6,7,4,8,9
第二次排序
我们这次分一组(无论怎么划分组,最后分的一组都是一个数字是一组)
最后一次排序相当于直接插入排序,这个时候因为待排序的数字集已经变得较为有序,所以算法的排序性能越好,这里对直接插入排序就不多说了
排序结果:2,4,5,6,7,8,9
参考代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LENGTH 15 //待排序的数字个数
void Shell(int arr[],int len,int width) //一次分组排序
{
int i,j,tmp;
for(i=width;i<len;i++)
{
tmp = arr[i];
for(j=i-width;j>=0;j-=width)
{
if(arr[j]<=tmp)
{
break;
}
arr[j+width] = arr[j];
}
arr[j+width] = tmp;
}
}
void ShellSort(int arr[],int len) //希尔排序
{
for(int i=9;i>=1;i/=2)
{
Shell(arr,len,i);
}
}
void ShowSort(int arr[],int len) //打印
{
for(int i=0;i<len;i++)
{
printf("%2d ",arr[i]);
}
printf("\n");
}
int main()
{
srand((unsigned int)time(NULL));
int arr[LENGTH];
for(int i=0;i<LENGTH;i++)
{
arr[i] = rand()%100; //获得随机数
}
ShowSort(arr,LENGTH); //打印
ShellSort(arr,LENGTH); //希尔排序
ShowSort(arr,LENGTH);
return 0;
}