//希尔排序法--插入排序升级版
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
/*
强调:网上,书上的希尔排序法都有问题
希尔排序并非按一个增量d,将一个数组分成若干小的数组,对每个数组进行插入排序,
真正的希尔排序步骤
第一步,通过业界常规 d = 数组长度 / 3 + 1; 求出增量d
第二步:取数组第一个元素,按照增量d的间隔 组成一个新的数组,对这个数组进行增量排序
第三步:再次获取增量d d = d / 3 + 1; 还是获取数组的第一个元素 按照增量d的间隔 组成一个新的数组,对这个数组进行增量排序
第四步:重复第三步
注意:①每次插入排序的都是第一个元素对应的新数组,没有对第二个元素对应的数组(或者第n个元素对应的数组)进行排序
②希尔排序当d=1的时候 仍然执行了一轮,当d=1 其实就是对整个数组进行一次插入排序
我个人感觉这比插入排序还多了几步
*/
//打印数组
void Print(int * arr, int num){
if (arr == NULL)
{
printf("传入参数不可以为空!\n");
return;
}
int i = 0;
for (int i = 0; i < num; i++)
{
printf("%5d", *(arr + i));
}
printf("\n");
}
//希尔排序
void ShellSort(int *arr, int len){
//定义每次间隔元素的个数
int gap = len;
int i = 0, j = 0, temp = 0, k = 0, m = 0;
/*
这里使用do while的原因是希尔排序是当增量d=1时,排序完成(需要以d=1进行排序一次),
如果使用while,退出条件不好写(gap>1)显然少运行了d=1的情况
*/
do
{
//业界统一实验的间隔将是数组长度的1/3 平均最好情况 经过若干次后,收敛为1
gap = gap / 3 + 1;
for (m = 0; m < gap; m++)
{
//由第一组数据加上d1 获取第一组数据中的每个元素在后面组中对应位置的数据
for (i = gap + m; i < len; i += gap)
{
k = i;
temp = arr[k];
//此时 每间隔d1的元素正好是i循环的数组 对这个新数组中的元素执行插入排序
//i-gap是子数组的最大下标 现在要插入的元素的下标是i
for (j = i - gap; j >= 0 && arr[j] >= temp; j -= gap)
{
//插入排序
arr[j + gap] = arr[j];
k = j;
}
arr[k] = temp;
}
}
//打印数组
printf("\n第%d轮\n", gap);
Print(arr, len);
} while (gap>1);
}
void Test(){
int i = 0;
int arr[10] = { 0 };
//定义时间类型变量
time_t ts;
//生成随机数种子
srand((unsigned int)time(&ts));
for (i = 0; i < 10; i++)
{
arr[i] = (int)(rand() % 100);
}
//打印数组
printf("\n原始数据----\n");
Print(arr, 10);
//希尔排序
printf("希尔排序之后的数据\n");
//ShellSort(arr,10);
ShellSort2(arr, 10);
Print(arr, 10);
}
void main(){
Test();
system("pause");
}
![]()