排序之希尔排序

希尔排序

希尔排序是直接插入排序的升级,希尔排序的出现冲破了 O(n2) 时间的屏障, 它的思想是将待排序的序列分割成若干子序列,分割的方式是隔几个元素(相隔“增量”)取一个元素,然后依次进行直接插入排序,然后减小增量,循环进行上述的过程,直到增量为1。当增量为1是也就是对待排序的序列进行直接插入排序,那么排序之后的序列就肯定是有序的了。

随着增量的缩小会使整个序列达到基本有序,而直接插入排序在元素基本有序时的效率很高。因为当元素基本有序时,不需要进行大量的数据元素的搬移。比如假设现在有一个数组为{55, 43, 23, 56, 32, 67, 90, 11, 2, 34},现在第一次的增量为3,第一次把数组分成如下几组{55, 43, 23, 56, 32, 67, 90, 11, 2, 34}, 其中红色的为一组,蓝色的为一组,绿色的为一组,分别对他们进行直接插入排序,这就是希尔排序的一趟;然后增量减一,接着分成两组,继续进行排序,然后再次减一,这时候增量为1,也就是进行直接插入排序,下图就是一个完整的过程:
希尔排序
下面的是代码实现:

void ShellSort(int a[], int n) {
    int i, j, Increment;
    int temp;
    // 这里的增量的初始值元素个数除以3,之后是增量除以3作为下一次的增量
    for (Increment = n / 3; Increment > 0; Increment = Increment / 3) {
        for (i = Increment; i < n; i++) {
            temp = a[i];
            for (j = i; j >= Increment; j -= Increment)
                if (temp < a[j - Increment])
                    a[j] = a[j - Increment];
                else
                    break;
            a[j] = temp;
        }
    }
}

从上面的图中可以看出,在增量为2时,整个序列已经基本有序,而最后一趟直接插入排序做的也就是相邻元素的交换。

希尔排序的时间复杂度

希尔排序的关键是不是随便分组后排序的,而是将相隔某个“增量”的元素组成一个序列,实现跳跃式的移动,使得排序的效率提高。
所以,这里的增量的选取就是相当关键的,上述的代码中增量的选取是Increment / 3。但是这也不是一个最好的方式,希尔排序增量序列的选取迄今为止是一个数学上的难题。在大量的研究之后,选取Hibbard增量序列,即 dlta[k]=2tk+11 时,可以获得不错的效率,它的最坏的时间复杂度为 O(N3/2) ,要比直接插入排序的 O(N2) 好。由于是跳跃式的分组排序,所以希尔排序不是一个稳定的排序。在这里给出按照Hibbard增量序列排序的代码:

void ShellInsert(int a[], int dlta, int n) {
    int i, j, temp;
    for (i = dlta; i < n; i++) {
        temp = a[i];
        for (j = i; j >= dlta; j -= dlta)
            if (temp < a[j - dlta])
                a[j] = a[j - dlta];
            else
                break;
        a[j] = temp;
    }
}

int Hibbard(int t, int k) {
    return (int) (pow(2, t - k + 1) - 1);
}
void ShellSort (int a[], int n) {
    int t = log(n + 1) / log(2);    // 排序需要进行log2(n+1),这里有一个数学计算
    int i;
    for (i = 1; i <= t; i++) 
        ShellInsert(a, Hibbard(t, i), n);
}

源码链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值