希尔排序是在1995年希尔教授(shell)提出来的,它是对插入排序算法的一种优化,同时也是属于不稳定排序中的一种。
基本思想如下:
第一步:需要在一连串毫无顺序的数字排列中取一个增量increment,把相隔increment的数字划分出来成为一个个子序列,把每个子序列用插入排序的排好序列,由于此时increment比较高,子序列中元素较少。
第二步:缩小增量,再以increment为间隔划分子序列,再把每个子序列用插入进行排序,由于increment变小了,所以子序列中药排序的元素就变多了。
第三步:不断缩小增量increment、划分、排序,直到increment = 1进行最后一个排序,此时整个序列中,大部分已经排序完毕,因此最后一次排序基本不用什么对换操作了。
假如此时有一个随机序列 {69,56,12,136,3,55,46,99,98,25},现在就用希尔排序来完成有小到大的排列。
第一步,确定增量increment,这个可以由序列元素的个数num来决定,increment = num / 2 = 5,再以5这个增量为间隔进行子序列划分,也就是说,从第0个元素开始,间隔为5的就可以划分成同一个子序列。
此时的子序列中就有{69,55} 、 {56,46}、 {12,99}、 {136,98}、 {3,25};
接下来就需要用插入排序法将每一个子序列进行排序,按照由小到大调整各自的所在的位置;
第一步排序后的序列,如下图:
第二步,缩小增量,按照shell教授的建议,increment = increment / 2向下取整,当然这并不是最优的取法,不同的增量选取会让希尔排序产生不一样的效率,这里我们姑且选用increment = increment/2 = 2,然后划分子序列。
此时的子序列中就有{55,12,3,56,136}和{46,98,69,99,25};
接下来就需要用插入排序法将每一个子序列进行排序,按照由小到大调整各自的所在的位置;
第二步排序后的序列,如下图:
到了这里会发现,这时候的序列有了一个从小到大的形,大部分元素已经是排好了。
第三步,increment = increment / 2 = 1,此时的子序列就是一整个序列,只要按照直接插入法排序便可,由于之前的两步已经做好了大部分的排序工作,这时候排序的工作量就会少之又少,只需要稍微移动几个元素的位置就可以了,这个就是希尔排序的优势所在。
以下是C语言代码实现过程:
void Into_Sort(int array[],int num)
{
int i=1,j=i-1,temp;
if(array[i] < array[j]) //先判断第一和第二个元素的大小关系
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
for(i=2;i<num;i++) //从第三个元素开始
{
j = i-1;
while(j>=0)
{
if(array[i] < array[j] && array[i] > array[j-1])
{
temp = array[i];
for(int k=i-1;k>=j;k--)
{
array[k+1] = array[k]; //将元素们往后移一位
}
array[j] = temp;
break;
}
j--;
}
}
}
我在主函数中,让其随机产生1000个随机数,通过希尔排序来进行排序
#include "Shell_Sort.h"
int main()
{
int num;
int shell[1000] = {0};
srand((unsigned)time(NULL));
//产生1000个元素的随机数组
for(num=0;num<10000;num++)
{
shell[num] = rand()%1000;
}
Shell_Sort(shell,1000);
printf("希尔排序后的结果是:\n");
for(num=0;num<1000;num++)
{
printf("%d ",shell[num]);
}
return 0;
}