开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情
经常使用的划分标准:
-
gap = count(list)/3 +1; gap = gap/3+1 -
gap = count(list)/2;gap = gap/2
思路:
实质是分组做插入算法,缩小分割值,继续插入排序处理。
首先计算出一个间隔(gap)数,即每组有gap个对象。对间隔gap的对象做直接插入排序,需要进行gap次。
缩小gap值,继续重复上述过程.
直至gap为1时,进行一次直接插入算法,此时基本无序列表已经排序好,处理会比较快速。
过程:
五个对象(0-5)的序列,gap等于2,也就是序号0,2,4做直接插入排序,然后1,3做直接插入排序。
当gap=1,处理过程是直接插入排序,排序完成。
代码例程:
#include<stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <string.h>
#include <errno.h>
#define SWAP(a1, a2, type) do {type temp = a1; a1 = a2; a2 = temp;} while(0)
int Cnt = 0;
int NumArr[200] = {0};
void PrintNums()
{
for(int i = 0;i < Cnt;i++){
fprintf(stdout," %d-",NumArr[i]);
}
}
//计算 gap == n/2
int ShellSort(int Cnt,int* ArrPtr)
{
//计算 间隔值
for(int gap = Cnt/2;gap > 0;gap = gap>>1){
//fprintf(stderr,"gap[%d]\n",gap);
//确定组间的起始比较序列,用来确定子序列
for(int a =0;a < gap;a++){
//fprintf(stderr,"gap[%d]a[%d]\n",gap,a);
//开始 直接插入排序 操作,这俩循环用于直接插入排序
for(int c = a + gap; c< Cnt;c += gap){
// fprintf(stderr,"gap[%d]a[%d]]c[%d]\n",gap,a,c);
for(int d = c;0 < d;d -= gap){
// fprintf(stderr,"d[%d]\n",d);
if(NumArr[d] < NumArr[d-gap]){
SWAP(NumArr[d],NumArr[d-gap],int);
}else{
break;
}
}
}
}
}
return 0;
}
int main(int argc, char** argv)
{
if(argc == 1) {
fprintf(stderr,"%s:need a some arg\n",argv[0]);
exit(1);
}
int CntTemp = Cnt = argc -1;
for(int i = 0;i < Cnt;i++){
NumArr[i] = atoi(argv[i+1]);
}
fprintf(stdout,"【Shell Sort】inputNum:");
PrintNums();
fprintf(stdout,"\n");
ShellSort(Cnt,NumArr);
fprintf(stdout,"result:");
PrintNums();
fprintf(stdout,"\n");
return 0;
}
测试结果
平均时间复杂度为O(nlogn),最好时间复杂度为O(n),最坏时间复杂度为 O(nlog2n)。在分组交叉比较的过程中,可能出现相对次序改变的情况,所以说希尔排序是不稳定的算法。
开始时分割值大一点,加快局部有序,不可一步分布过小。
希尔排序是对直接插入排序的优化算法,加快比较交换的效率,相比直接插入排序更适合处理大型数据的排序。