希尔排序

基本概念:

希尔排序按其设计者希尔(Donald Shell)的名字命名,它是一种基于插入排序的快速排序算法,要了解希尔排序,必须先掌握插入排序的原理与实现

 

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

 

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作(且步长要小于数组长度)。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

 

关于希尔排序的时间复杂度,与步长息息相关:

 

过程如图:

 

简单例子分析:

待排序数组:
{6, 5, 3, 1, 8, 7, 2, 4, 9, 0}

第一次步长h=4,
那么数组按照步长可以拆分成4个小数组([0]6的意思是下标[0]的值为6)

{[0]6, [4]8, [8]9}
{[1]5, [5]7, [9]0}
{[2]3, [6]2}
{[3]1, [7]4}

对这4个小数组分别进行插入排序后,4个小数组变成:
{[0]6, [4]8, [8]9}
{[1]0, [5]5, [9]7}
{[2]2, [6]3}
{[3]1, [7]4}
合并起来就是:{6, 0, 2, 1, 8, 5, 3, 4, 9, 7}

第二次步长h=1,
那么数组按照步长只有1个数组了
{6, 0, 2, 1, 8, 5, 3, 4, 9, 7}

对这个数组进行一次插入排序后,最终顺序就成为:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

#include <stdio.h>
 
void shell_sort(int arr[], int size)
{
    if (arr == NULL)
        return ;
    int h = 1; /* 关于步长,取值没有统一标准,必须小于size,最后一次步长要为1 */
    
    /* 计算首次步长 */
    while (h < size/3)
        h = 3*h + 1;
 
    int i, j, temp;
    while (h >= 1) {
        for (i = h; i < size; ++i) {
            /* 将a[i]插入到a[i-h]、a[i-2h]、a[i-3h]...中 */ 
            for (j = i; j >= h && (arr[j] < arr[j-h]); j -= h) {
                temp = arr[j];
                arr[j] = arr[j-h];
                arr[j-h] = temp;
            }
        }
 
        /* 每轮内循环后输出数组的现状 */
        int k;
        printf("the step=%d : ", h);
        for (k = 0; k < size; ++k) {
            printf("%d ", arr[k]);
        }
        printf("\n");
 
        /* 计算下一轮步长 */
        h = h / 3;
    }
 
}
 
int main()
{
    int arr[] = {6, 5, 3, 1, 8, 7, 2, 4, 9, 0};
    int size = sizeof(arr) / sizeof(int);
 
    //sort
    shell_sort(arr, size);
 
    //print
    int i = 0;
    for (i; i < size; ++i) {
        printf("%d\n", arr[i]);
    }
 
    return 0;
}

编译运行:

 

原文出自:http://blog.csdn.net/daiyudong2020/article/details/52445044

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值