【排序算法】希尔排序

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

对于大规模的乱序数组,插入排序很慢,因为它只会交换相邻元素,因此元素只能一点一点地从数组的一端移动到另一端。比如主键最小的元素正好在数组的另一端,那么它就得移动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次交换。

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

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

相关推荐
皮皮林5514 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河5 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
地平线开发者5 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮6 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者6 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考6 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
桦说编程7 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅9 小时前
Java面向对象入门(类与对象,新手秒懂)
java
HXhlx10 小时前
CART决策树基本原理
算法·机器学习