希尔排序增量序列简介

希尔排序可谓是时间复杂度较难分析的一类排序算法之一,其原因在于其增量序列的多样性和构造的复杂性。下面笔者将对几种流传较广的希尔排序的增量序列进行简单的介绍并给出它们的实现代码。

希尔排序主过程代码如下:

#define ShellSort(IncrementName,delta) \
{ \
    for(int d=delta>0?1:IncrementSequence_##IncrementName[0]; \
        delta>0&&d<=IncrementSequence_##IncrementName[0]||delta<0&&d>0;d+=delta) \
        for(int sub=IncrementSequence_##IncrementName[d]+1;sub<=n;sub++) \ { \
            int obj,temp=array[sub]; \
            for(obj=sub;obj>IncrementSequence_##IncrementName[d] \
                &&array[obj-IncrementSequence_##IncrementName[d]]>temp; \
                obj-=IncrementSequence_##IncrementName[d]) \
                array[obj]=array[obj-IncrementSequence_##IncrementName[d]]; \
            array[obj]=temp; \
        } \
}

Shell 增量序列

Shell 增量序列的递推公式为:

ht=N2,hk=hk+12

Shell 增量序列的最坏时间复杂度为 Θ(N2)

Shell 增量序列构造代码如下:

int IncrementSequence_Shell[35];
void IncrementSequenceBuild_Shell()
{
    IncrementSequence_Shell[0]=1;
    IncrementSequence_Shell[1]=n;
    while(IncrementSequence_Shell[IncrementSequence_Shell[0]]>1)
        IncrementSequence_Shell[++IncrementSequence_Shell[0]]=IncrementSequence_Shell[IncrementSequence_Shell[0]-1]/2;
}

调用代码如下:

IncrementSequenceBuild_Shell();
ShellSort(Shell,1)

Hibbard 增量序列

Hibbard 增量序列的通项公式为:

hi=2i1

Hibbard 增量序列的递推公式为:


h1=1,hi=2hi1+1

Hibbard 增量序列的最坏时间复杂度为 Θ(N3/2) ;平均时间复杂度约为 O(N5/4)

Hibbard 增量序列构造代码如下:

int IncrementSequence_Hibbard[35];
void IncrementSequenceBuild_Hibbard()
{
    IncrementSequence_Hibbard[0]=30;
    IncrementSequence_Hibbard[1]=1;
    for(int i=2;i<=30;i++)
        IncrementSequence_Hibbard[i]=IncrementSequence_Hibbard[i-1]*2+1;
}

或者直接打表:

int IncrementSequence_Hibbard[]={30,
    1,3,7,15,31,63,127,255,
    511,1023,2047,4095,8191,16383,32767,65535,
    131071,262143,524287,1048575,2097151,4194303,8388607,16777215,
    33554431,67108863,134217727,268435455,536870911,1073741823};

调用代码如下:

IncrementSequenceBuild_Hibbard();
ShellSort(Hibbard,-1)

Knuth 增量序列

Knuth 增量序列的通项公式为:

hi=12(3i1)

Knuth 增量序列的递推公式为:


h1=1,hi=3hi1+1

Knuth 增量序列构造代码如下:

int IncrementSequence_Knuth[25];
void IncrementSequenceBuild_Knuth()
{
    IncrementSequence_Knuth[0]=20;
    IncrementSequence_Knuth[1]=1;
    for(int i=2;i<=20;i++)
        IncrementSequence_Knuth[i]=IncrementSequence_Knuth[i-1]*3+1;
}

或者直接打表:

int IncrementSequence_Knuth[]={20,
    1,4,13,40,121,364,1093,3280,
    9841,29524,88573,265720,797161,2391484,7174453,21523360,
    64570081,193710244,581130733,1743392200};

调用代码如下:

IncrementSequenceBuild_Knuth();
ShellSort(Knuth,-1)

Gonnet 增量序列

Gonnet 增量序列的递推公式为:

ht=N2.2,hk=hk+12.2(h2=2h1=1)

Gonnet 增量序列构造代码如下:

int IncrementSequence_Gonnet[30];
void IncrementSequenceBuild_Gonnet()
{
    IncrementSequence_Gonnet[0]=1;
    IncrementSequence_Gonnet[1]=n;
    while(IncrementSequence_Gonnet[IncrementSequence_Gonnet[0]]>1)
        IncrementSequence_Gonnet[++IncrementSequence_Gonnet[0]]=IncrementSequence_Gonnet[IncrementSequence_Gonnet[0]-1]/2.2;
    IncrementSequence_Gonnet[IncrementSequence_Gonnet[0]]=1;
}

调用代码如下:

IncrementSequenceBuild_Gonnet();
ShellSort(Gonnet,1)

Sedgewick 增量序列

Sedgewick 增量序列的通项公式为:

hi=max(94j92j+1,4k32k+1)

Sedgewick 增量序列的最坏时间复杂度为 O(N4/3) ;平均时间复杂度约为 O(N7/6)

Sedgewick 增量序列构造代码如下:

int IncrementSequence_Sedgewick[30];
void IncrementSequenceBuild_Sedgewick()
{
    IncrementSequence_Sedgewick[0]=28;
    IncrementSequence_Sedgewick[1]=1;
    for(int i=1,j=2;i<=13||j<=15;)
        if(i<=13&&9*(1<<i*2)-9*(1<<i)+1<(1<<j*2)-3*(1<<j)+1)
            IncrementSequence_Sedgewick[i+j-1]=9*(1<<i*2)-9*(1<<i)+1,i++;
        else
            IncrementSequence_Sedgewick[i+j-1]=(1<<j*2)-3*(1<<j)+1,j++;
}

或者直接打表:

int IncrementSequence_Sedgewick[]={28,
    1,5,19,41,109,209,505,929,
    2161,3905,8929,16001,36289,64769,146305,260609,
    587521,1045505,2354689,4188161,9427969,16764929,37730305,67084289,
    150958081,268386305,603906049,1073643521};

调用代码如下:

IncrementSequenceBuild_Sedgewick();
ShellSort(Sedgewick,-1)
点赞