希尔排序
希尔排序又称为缩小增量排序
希尔排序的基本思想:希尔排序本质上还是插入排序,只不过是把待排序序列分成几个子序列,再分别对这几个子序列进行直接插入排序。
排序过程
①先以增量5来分割序列,也就是下标为0,5,10,15...的关键字分成一组,下标为1,6,11,16..分成一组,然后对这些组分别进行直接插入排序,这就完成了一轮希尔排序。
②缩小增量(d1=n/2,di+1= di/2(向下取整),比如10个数据序列,第一次增量d1=10/2=5,第二次增量d2= d1/2(向下取整)= 5/2(向下取整)=2,并且最后一个增量等于1),所以第二轮以增量为2进行类似的排序过程。
③接下来的第三轮,第四轮...都是类似的过程,直到最后一轮以增量为1。此时就是前面所说的直接插入排序。
希尔排序的性能分析
希尔排序的每一轮都会使整个序列变得越来越有序,最后一轮当增量为1的时候,整个序列几乎都是有序的,所以进行直接插入排序会提高排序的效率。
时间复杂度:... 希尔排序的时间复杂度约为O(n1.3) 在最坏情况下希尔排序的时间复杂度为O(n2)
空间复杂度:希尔排序的空间复杂度为O(1)
稳定性:不稳定,由于不同的增量可能就会把相等的关键字划分到两个直接插入排序中进行
排序, 可能就会造成相对顺序变化。
例如:5 2 2 3 第一趟以2为增量排序后 2 2 5 3 再以增量为1排序后2 2 3 5
代码实现
#include <stdio.h>
#define MAXSIZE 8
typedef int KeyType; //定义关键字类型
typedef struct //记录类型
{
KeyType key; //关键字项
} ElemType; //排序的记录类型定义
/*
直接插入排序
参数说明:
arr:传入要排序的数组
n:数组的大小
*/
void ShellSort(ElemType A[] , int n)
{
//对顺序表做希尔插入排序,本算法和直接插入排序相比,做了以下修改
/*
1、前后记录位置的增量是dk,不是1
2、A[0]只是暂存单元,不是哨兵,当j<=0,插入位置已到
*/
int dk,i,j;
for(dk=n/2;dk>=1;dk/=2){ //步长变化
for (i=dk+1;i<=n;++i){
if(A[i].key<A[i-dk].key){//需将A[i] 插入有序增量子表
A[0]=A[i];//暂存在A[0]
for(j=i-dk;j>0&&A[0].key<A[j].key;j-=dk){
A[j+dk]=A[j];//记录后移,查找插入的位置
}
A[j+dk]=A[0]; //插入
}
}
}
}
int main()
{
ElemType A[MAXSIZE] = {0};
int arr[] = {0,6,5,12,3,2,1,9};
int i;
printf("-----------------希尔排序----------------\n" );
printf("排序前:");
for(i = 1; i < MAXSIZE; i++)
{
A[i].key = arr[i];
printf("A[%d].key = %d\t" , i , A[i].key);
}
printf("\n");
//插入排序
ShellSort(A, MAXSIZE);
printf("排序后:");
for(i = 2; i < MAXSIZE+1; i++)
{
printf("A[%d].key = %d\t" , i-1 , A[i].key);
}
return 0;
}