排序算法3.5:希尔排序

  • 简介

希尔排序是插入排序的一种更高效的改进算法。对于插入排序来说,最好的情况是待排序数组本身已大部分有序或完全有序。此时进行排序接近线性排序,时间复杂度为O(n)。希尔排序的目的,就是将数组最后转换为这样的形式 ,使得插入排序的效率更高。先宏观调整,再微观调整。

关于希尔排序中最重要的变量是步长,它是逐渐减小的,每一趟排序的步长都必定比上一趟小,最终成为1.根据步长将原数组分为小段,对每一段进行直接插入排序,随后减小步长,对每一段进行直接插入排序...重复以上过程,当步长成为1的时候此时数组已经大部分有序了,尽可能的使最后这一趟插入排序的时间复杂度接近O(n).

  • 关于希尔排序中步长的选取

步长的选取并没有绝对的规定和规律,只需最后步长可以变为1即可。WikiPedia上记载的有12种。

一般来说步长的选取是有以下2种情况。

①:

希尔排序的发明者最初提议是n/2即取数组长度的一半,直到变为1为止。虽然这样选取确实最后时间复杂度、数据的交换次数和比较次数都比直接插入排序好,但是仍然有改进的余地。

②:

已知的最好步长串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),该串行的项来自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 这两个算式[1].这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”

我们平常使用的时候没有特殊需要,只需将步长设置为n/2即可。

  • 具体代码实现(步长n/2,升序,使用数组)
void ShellSort(int arr[],int len)
{
    int gap = len/2;
    while(gap >= 1)
    {
        for(int i = gap;i < len;i++)
        {
            for(int j = i;j >= gap && (arr[j - gap] > arr[j]); j-=gap)
            {
                int get = arr[j];
                arr[j] = arr[j-gap];
                arr[j-gap] = get;
            }
        }
        gap/=2;
    }
}

这是最简单的希尔排序实现。先指定gap的初值,再在while循环中不断减小直至为1.内部的设计非常巧妙,外层for循环定义i从gap处开始,每次循环完成后+1,在一次内层循环中则是将gap处的元素和它前面的元素进行比较,满足条件时进行交换,完成了“将数组分为多个子数组后,先将子数组排序”的过程。

随着gap的不断减小,子数组也越来越小。不断重复进行排序之后,gap变为1.此时的数组应当已经是大部分有序(完全有序也有可能)。当gap为1的时候,外层循环完美模拟了直接插入排序的过程:将第一个元素空出来,作为有序数列的首元素;每次的i代表待插入元素的下标。进入内部循环,如果满足条件的话定义get先将待插入的数保存起来防止丢失,然后直接进行交换,直至将数据交换到正确的位置。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值