十大排序算法之 希尔排序

75 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情

经常使用的划分标准:

  1. gap = count(list)/3 +1gap = gap/3+1
    
  2. gap = count(list)/2gap = 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;

}

测试结果

image.png 平均时间复杂度为O(nlogn),最好时间复杂度为O(n),最坏时间复杂度为 O(nlog2n)。在分组交叉比较的过程中,可能出现相对次序改变的情况,所以说希尔排序是不稳定的算法。

开始时分割值大一点,加快局部有序,不可一步分布过小。

希尔排序是对直接插入排序的优化算法,加快比较交换的效率,相比直接插入排序更适合处理大型数据的排序。