【算法系列】排序算法(3)希尔排序

排序(3) 希尔排序
一、前言

希尔(Shell)又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版
希尔排序,也称递减增量排序算法,以其设计者希尔(Donald Shell)的名字命名,该算法于1959年公布。

图片来自维基百科
图片来自维基百科

二、算法思想

对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长),将待排序元素分成若干组子序列,所以距离为gap的倍数的记录放在同一组中;然后,对各组内的元素进行直接插入排序。

这一趟排序完成之后,每一组内的元素都输有序的。然后减少gap的值,并重复执行上述的分组和排序。重复这样的操作直到gap=1时,整个序列就是有序的。

注意:
不要与归并排序相混淆,两者本质上是不一样的:归并排序的分是将相邻的元素化为一组,而希尔排序则是按照步长来分组的。
打个比方,军训的时候,教官从第一个人数到第八个人然后说“你们一组”,这是归并排序
希尔排序则是,教官说“从第一个人开始,依次报数,奇数的是一组”。

时间复杂度:
对插入算法的改进,低于O(n^2),具体与选择的增量序列有关。

稳定性:
不稳定

使用场景:
时间复杂度和增量序列的联系紧密,好的增量序列才能保证有好的时间复杂度,使用较少。

具体实例演示:
下面用希尔排序来对数组 {13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10} 排序(按照2i的分组序列)

Step 1
首先,我打算分为两个一组,共有16个数,就是八组,步长为8。
{13,65} {14,23} {94,45} {33,27} {82,73} {25,25} {59,39} {94,10}

组内用直接插入排序,得到
{13,65} {14,23} {45,94} {27,33} {73,82} {25,25} {39,59} {10,94}

Step 2
第二步,将新序列分为四个一组,共有四组,步长为4
{13,45,73,39} {65,94,82,59} {14,27,25,10} {23,33,25,94}

组内用直接插入排序,得到
{13,39,45,73} {59,65,82,94} {10,14,25,27} {23,25,33,94}

Step 3
第三步,八个一组,共两组,步长为2
{13,45,59,82,10,25,23,33} {39,73,65,94,14,27,25,94}

组内用直接插入排序,得到
{10,13,23,25,33,45,59,82} {14,25,27,39,65,73,94,94}

Step 4
第四步,16个一组,共一组,得到
{10,13,23,25,33,45,59,82,14,25,27,39,65,73,94,94}

组内用直接插入排序,得到
{10,13,14,23,25,25,27,33,39,45,59,65,73,82,94,94}
排序完成。

三、代码
/*
    希尔排序
    Time : 2018-2-20
    Author : Stell Chen
    Content : a simple example of Shell sort.
*/

#include<stdio.h>

/*
    a[] 为待排序数组
    n 为数组长度
*/
void shell_sort(int a[], int n) {
    int i, j, gap;

    //确定每次分组的步长->gap既相当于分多少组
    for (gap = n/2; gap > 0; gap/=2)
    {
        printf("\n\n步长为%d\n", gap);
        //对分组进行排序,使每组都形成一个有序的序列
        for (i = 0; i < gap; i++)
        {
            //如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移
            for ( j = i+gap; j < n; j+=gap)
            {
                if (a[j] < a[j - gap]) {
                    int temp = a[j];
                    int k = j - gap;
                    while (a[k] > temp && k >= 0) {
                        a[k + gap] = a[k];
                        k -= gap;
                    }
                    a[k + gap] = temp;
                }
            }
        }
        printf("排序中:\n");
        for (int i = 0; i < 8; i++)
            printf("%d ", a[i]);
    }

}

int main() {
    int a[8] = { 13,14,94,33,82,25,59,65 };

    printf("排序前:\n");
    for (int i = 0; i < 8; i++)
        printf("%d ", a[i]);
    shell_sort(a, 8);

    printf("\n\n排序后:\n");
    for (int i = 0; i < 8; i++)
        printf("%d ", a[i]);

    return 0;
}

执行结果如下:
这里写图片描述

四、参考文章

1.维基百科
https://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
2.排序(3)希尔排序
http://cuijiahua.com/blog/2017/12/algorithm_3.html
3.希尔排序
http://www.cnblogs.com/skywang12345/p/3597597.html
4.逍遥游——经典排序算法 - 希尔排序Shell Sort
https://blog.newnius.com/shell-sort.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值