插入排序与希尔排序详解

参考文章:点击打开链接

1、基本思想:

希尔排序也成为“缩小增量排序”,其基本原理是,现将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个待排序列“基本有序”后,最后在对所有元素进行一次直接插入排序。因此,我们要采用跳跃分割的策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。希尔排序是对直接插入排序算法的优化和升级。
所谓的基本有序,就是小的关键字基本在前面,大的基本在后面,不大不小的基本在中间,例如{2,1,3,6,4,7,5,8,9,}就可以称为基本有序了。但像{1,5,9,3,7,8,2,4,6}这样,9在第三位,2在倒数第三位就谈不上基本有序。

2、复杂度分析:

希尔排序的关键并不是随便分组后各自排序,而是将相隔某个“增量”的记录组成一个子序列,实现跳跃式移动,使得排序的效率提高。需要注意的是,增量序列的最后一个增量值必须等于1才行。另外,由于记录是跳跃式的移动,希尔排序并不是一种稳定的排序算法。

希尔排序最好时间复杂度和平均时间复杂度都是

插入排序与希尔排序详解_子序列

,最坏时间复杂度为

插入排序与希尔排序详解_子序列_02


3、排序过程如下:

以数组{26, 53, 67, 48, 57, 13, 48, 32, 60, 50 }为例,步长序列为{5,2,1}

初始化关键字: [26, 53, 67, 48, 57, 13, 48, 32, 60, 50 ]

插入排序与希尔排序详解_子序列_03

最后的排序结果:
13 26 32 48 48 50 53 57 60 67

希尔排序是优化过的插入排序

下面详细说明 插入排序如何一步一步优化为希尔排序

过程清晰 流程简单

//直白的插入排序
void insertSort(int arr[], int length){

    for (int i = 1; i < length; i++) {

        int temp = arr[i];
        int j = i;

        //这里需要注意j的终止条件是 j-1>=0 既j>0
        for (; j > 0 && arr[j - 1] > temp; j--) {
            arr[j] = arr[j - 1];//后面的值赋值给前面
        }

        arr[j] = temp;

    }
}
//对插入排序做变形
//为适应 增量间隔排序做变型 此处的1即为间隔增量的值
void insertSort(int arr[], int length){

    for (int i = 1; i < length; i++) {

        int temp = arr[i];
        int j = i;

        //j 最小值 为 1
        for (; j - 1 >= 0 && arr[j - 1] > temp; j -= 1) {
            arr[j] = arr[j - 1];//后面的值赋值给前面
        }

        arr[j] = temp;

    }
}
//对插入排序添加增量间隔 将上面的1替换为incrementGap变量
//带增量间隔的插入排序
void incrementGapInsertSort(int arr[], int length){

    int incrementGap = 0;

    //将间隔增量1替换为变量 替换后的代码
    //固定间隔增量的插入排序
    for (int i = incrementGap; i < length; i++) {

        int temp = arr[i];
        int j = i;

        //j 最小值为incrementGap
        //相隔incrementGap个数做一次比较
        for (; j - incrementGap >= 0 && arr[j - incrementGap] > temp; j -= incrementGap) {
            arr[j] = arr[j - incrementGap];//后面的值赋值给前面
        }

        arr[j] = temp;
    }
}
//将间隔增量采用递减的方式进行处理 间隔增量最小值必须为1 
//希尔排序 到此就将一个插入排序一步一步的改为了希尔排序
void shellSort(int arr[], int length){

    int incrementGap = 0;

    //将间隔增量采用递减的方式进行处理 间隔增量最小值必须为1 希尔排序
    for (incrementGap = length / 2; incrementGap > 0; incrementGap /= 2) {
        for (int i = incrementGap; i < length; i++) {

            int temp = arr[i];
            int j = i;

            //j 最小值为incrementGap
            //相隔incrementGap个数做一次比较
            for (; j - incrementGap >= 0 && arr[j - incrementGap] > temp; j -= incrementGap) {
                arr[j] = arr[j - incrementGap];//后面的值赋值给前面
            }

            arr[j] = temp;
        }
    }

    for (int j = 0; j < length; j++) {
        printf("arr is %d\n", arr[j]);
    }
}