一、概念及说明
希尔排序-----插入排序的一种,属于优化后的插入排序
原理:把数组中的数据进行分组,在组内进行排序,没有排列好继续分组(注意改分组需要调整每个组元素的个数),每次排序都是在组内进行排序
例如数组中有15个元素为例,第一次分组为 15/2 =7-1=6 第二次分组为7/2=3-1=2 算出来的数为元素间隔数。
相比于插入排序的优点是:1.减少查找次数 2.减少元素移动的次数
二、使用说明
1.时间复杂度
当增量大于1的时候,关键字较小的记录就不是一步步地挪动,而是跳跃式地移动,从而使得在进行最后一趟增量为1的的插入排序中,序列已经基本有序,只要做少量的比较和移动即可完成排序,因此希尔排序的排序的时间复杂度比直接插入排序的低。希尔排序的时间复杂度取决于增量的选取。当n在某个特定的范围内,希尔排序所需的比较和移动次数大概为n^1.3。
2.空间复杂度
只需要一个记录的辅助空间r[0],所以空间复杂度为O(1)。
3.算法特点
- 记录跳跃式地移动导致排序方法是不稳定的。
- 只能用于顺序结构,不能用于链式结构。
- 增量序列可以有各种取法,但应该使增量序列中的值没有除1之外的公因子,并且最后一个增量值必须等于1。
- 记录总的比较次数和移动次数比直接插入排序要少,n越大时,效果越明显。所以适合初始记录无序、n较大时的情况。
4.动画演示
三、代码演示
#include <stdio.h>
#include <stdlib.h>
void GroupSort(int* arr, int len, int iStep, int i)
{
int ii = 0, jj = 0;
int temp = 0;
//这里面相当于插入排序
for (ii = i + iStep; ii < len; ii += iStep)
{
temp = arr[ii];
for (jj = ii - iStep; jj >= 0; jj -= iStep)
{
if (arr[jj] <= temp)
break;
arr[jj + iStep] = arr[jj];
}
arr[jj + iStep] = temp;
}
}
/*
* ShellSort()和GroupSort()是将希尔排序分步来做
* 先分组,再将组内的元素进行插入排序,增量从大到小,就完成了排序
*/
void ShellSort(int *arr,int len)
{
int iStep;
int i;
//这里面进行的是分组任务
for (iStep = len / 2; iStep > 0; iStep = iStep / 2)
{
for ( i = 0; i < len; ++i)
{
GroupSort(arr,len,iStep,i);
}
}
}
/*
* 整个希尔排序的过程如下
*/
void shellSort(int *array, int len)
{
int i, j, k, temp, gap;
for (gap = len / 2; gap >= 1; gap /= 2)
{
for (k = 0; k < len; ++k){
for (i = k + gap; i < len; i += gap)
{
temp = array[i];
for (j = i - gap; j >= 0 && temp < array[j]; j -= gap)
array[j + gap] = array[j];
array[j + gap] = temp;
}
}
}
}
void printArray(int *array,int len)
{
for (int i = 0; i < len; ++i)
{
printf("%4d", array[i]);
}
}
int main(void)
{
int array[10] = { 78,15,99,53,84,27,39,1,41,67 };
int len = sizeof(array) / sizeof(int);
//输出排序前的数组
printf("排序前的数组\n");
printArray(array, len);
putchar('\n');
//调用希尔排序函数排序
//shellSort(array, len);
ShellSort(array, len);
//输出排序后的数组
printf("排序后的数组\n");
printArray(array, len);
putchar('\n');
system("pause > 0");
return 0;
}
代码运行结果如下: