希尔排序

希尔排序是插入排序的一种,又叫缩小增量排序,也是对直接插入排序的一种优化,下面是插入排序的一些特征:

  • 时间复杂度不确定,看具体实现,依赖于增量序列函数,本文实现的时间复杂度为O(n^2),若步长选取为 2^k+1, ..., 5, 3, 1 其时间复杂度为 O(n1.5),当n在某个特定范围时,有些实现可以达到O(n1.3)
  • 空间复杂度,最好最坏平均都为:O(1)
  • 是否稳定:不稳定

每次排序,数据都会变得更加有序

希尔排序的基本思想:先将待排序表每隔一定距离取一个数据,形成一个子表,整个表化为许多子表,然后对每个子表分别进行直接插入排序,步长越来越小,最后为1时,对表整个表进行一次直接插入排序。

有人可能会觉得这不是简单问题复杂化吗?并不是,因为直接插入排序算法适用于基本有序数据量不大的排序表,适用于的意思就是更快,所以可以利用这两个特性对直接插入排序进行优化,将一个子表变成多个子表,就是在缩小数据量,子表有序后,整个表就更加有序了。

子表选取例子:原表L(1,2,3,4,5,6,7,8,9)有九个元素,步长 dk 取 9/2 即 4,得到 4 个子表 L1(1,5,9), L2(2,6), L(3,7), L(4,8)

下面是一种希尔排序的代码,增量选取为 n/2, n/4, ..., 2, 1:

/**
* arr 数组首地址
* len 数组长度
*/
void shell_sort(int *arr, int len)
{
    int i, j;
    int dk;     // 记录步长
    for (dk=len/2; dk>=1; dk>>=1) { // 步长变化
        for (i=dk; i<len; i++) {
            if (arr[i] < arr[i-dk]) {
                int temp = arr[i];
                for (j=i-dk; j>=0 && temp<arr[j]; j-=dk)
                    arr[j+dk] = arr[j];
                arr[j+dk] = temp;
            }//if
        }//for
    }//for
}

测试代码,可直接复制后编译执行:

#include <stdio.h>

void show(int *arr, int len);
void insert_sort(int *arr, int len);

int main()
{
    int len = 7;
    int arr[] = {7, 10, 11, 9, -8, 2, 27};
    insert_sort(arr, len);
    show(arr, len);
    return 0;
}

/**
* arr 数组首地址
* len 数组长度
*/
void show(int *arr, int len)
{
    int i;
    for (i=0; i<len; i++) {
        printf("%4d", arr[i]);
    }
    printf("\n");
}

/**
* arr 数组首地址
* len 数组长度
*/
void shell_sort(int *arr, int len)
{
    int i, j;
    int dk;     // 记录步长
    for (dk=len/2; dk>=1; dk>>=1) { // 步长变化
        for (i=dk; i<len; i++) {
            if (arr[i] < arr[i-dk]) {
                int temp = arr[i];
                for (j=i-dk; j>=0 && temp<arr[j]; j-=dk)
                    arr[j+dk] = arr[j];
                arr[j+dk] = temp;
            }//if
        }//for
    }//for
}
posted @ 2020-11-14 17:01  七进制  阅读(84)  评论(0编辑  收藏  举报