【排序算法】希尔排序

希尔排序是一种基于插入排序的快速的排序算法。

对于大规模的乱序数组,插入排序很慢,因为它只会交换相邻元素,因此元素只能一点一点地从数组的一端移动到另一端。比如主键最小的元素正好在数组的另一端,那么它就得移动N-1次。希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

希尔排序的思想是使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。在排序时,如果h很大,就能将元素移动到很远的地方,为实现更小的h有序创造条件。用这种方法,对于任意以1为结尾的h序列,都能够将数组排序。这就是希尔排序。

实现希尔排序的一种方法是对于每个h,用插入排序将h个子数组独立的进行排序。但因为子数组是相互独立的,一个更简单的方法是在h-子数组中将每个元素将换到比它大的元素之前去。只需要在插入排序的代码中将移动距离由1改为h就可以,这样希尔排序的实现就转化为了一个类似于插入排序但使用不同增量的过程。

希尔排序更高效的原因就是它衡量了子数组的规模和有序性。排序之处,各个子数组都很短,排序之后的子数组都是部分有序的。这两种情况都很适合插入排序。子数组部分有序的程度取决于递增序列的选择。

还是以一个整数数组为例:

java 复制代码
public class Shell {
    public static void sort(int[] a)
    {
        int N=a.length;
        int h=1;
        while (h<N/3)
            h=3*h+1;
        while (h>=1)
        {
            for (int i=h;i<N;i=i+1)
            {
                for (int j=i;j>=h&&(a[j]<a[j-h]);j=j-h)
                    list_deal.exch(a,j,j-h);
                    list_deal.printArray(a);
            }
            h=h/3;
        }
    }
    public static void main(String[] args) {
        int[] a={534,745,264,864,136,967,254,745,734,269,538,265,825,158,139};
        list_deal.printArray(a);
        sort(a);
    }
}

排序过程:

java 复制代码
534 745 264 864 136 967 254 745 734 269 538 265 825 158 139 
158 745 264 864 136 967 254 745 734 269 538 265 825 534 139 
158 139 264 864 136 967 254 745 734 269 538 265 825 534 745 
136 139 264 864 158 967 254 745 734 269 538 265 825 534 745 
136 139 264 864 158 967 254 745 734 269 538 265 825 534 745 
136 139 254 864 158 967 264 745 734 269 538 265 825 534 745 
136 139 254 745 158 967 264 864 734 269 538 265 825 534 745 
136 139 254 745 158 967 264 864 734 269 538 265 825 534 745 
136 139 254 745 158 269 264 864 734 967 538 265 825 534 745 
136 139 254 745 158 269 264 864 734 967 538 265 825 534 745 
136 139 254 265 158 269 264 745 734 967 538 864 825 534 745 
136 139 254 265 158 269 264 745 734 967 538 864 825 534 745 
136 139 254 265 158 269 264 745 734 534 538 864 825 967 745 
136 139 254 265 158 269 264 745 734 534 538 864 825 967 745 
136 139 254 265 158 269 264 745 734 534 538 864 825 967 745 
136 139 254 265 158 269 264 745 734 534 538 864 825 967 745 
136 139 254 265 158 269 264 745 734 534 538 864 825 967 745 
136 139 158 254 265 269 264 745 734 534 538 864 825 967 745 
136 139 158 254 265 269 264 745 734 534 538 864 825 967 745 
136 139 158 254 264 265 269 745 734 534 538 864 825 967 745 
136 139 158 254 264 265 269 745 734 534 538 864 825 967 745 
136 139 158 254 264 265 269 734 745 534 538 864 825 967 745 
136 139 158 254 264 265 269 534 734 745 538 864 825 967 745 
136 139 158 254 264 265 269 534 538 734 745 864 825 967 745 
136 139 158 254 264 265 269 534 538 734 745 864 825 967 745 
136 139 158 254 264 265 269 534 538 734 745 825 864 967 745 
136 139 158 254 264 265 269 534 538 734 745 825 864 967 745 
136 139 158 254 264 265 269 534 538 734 745 745 825 864 967 

可以看到,总共有27次元素交换,而同样的数组用插入排序,需要63次交换。

与选择排序和插入排序形成对比的是,希尔排序也可以用于大型数组,它对任意排序的数组表现也很好。

希尔排序的另一个优点是代码量很小,且不需要使用额外的内存空间。

相关推荐
找不到、了8 分钟前
关于B+树的介绍
数据结构·b树·mysql
天天摸鱼的java工程师11 分钟前
秒杀系统中:如何防止超卖和库存超扣?
java·后端
弥彦_15 分钟前
贪心算法经典问题
c++·算法
CodeCipher19 分钟前
Java基础复习之继承
java·开发语言
BillKu26 分钟前
Java延时
java·开发语言
lboverfys28 分钟前
贪心算法之分发饼干(一)
算法·贪心算法
啾啾Fun36 分钟前
Java面试题:分布式ID时钟回拨怎么处理?序列号耗尽了怎么办?
java·分布式·分布式id·八股
这张生成的图像能检测吗1 小时前
生成对抗网络(GANs)入门介绍指南:让AI学会“创造“的魔法(二)【深入版】
人工智能·pytorch·深度学习·神经网络·算法·生成对抗网络·计算机视觉
qq_534452521 小时前
【算法 day02】LeetCode 209.长度最小的子数组 | 59.螺旋矩阵II
java·算法·leetcode·职场和发展
dying_man1 小时前
LeetCode--31.下一个排列
算法·leetcode