【排序算法】希尔排序

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

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

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

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

相关推荐
蒋士峰DBA修行之路2 分钟前
实验六 动态剪枝
数据库·算法·剪枝
superlls3 分钟前
(设计模式)区分建造者、 规格模式(MyBatis Example+Criteria )
java·tomcat
kimble_xia@oracle14 分钟前
SQL 笔记
java·数据库·oracle
David爱编程29 分钟前
深度解析:synchronized 性能演进史,从 JDK1.6 到 JDK17
java·后端
Tim_1030 分钟前
【算法专题训练】20、LRU 缓存
c++·算法·缓存
脑子慢且灵1 小时前
【JavaWeb】一个简单的Web浏览服务程序
java·前端·后端·servlet·tomcat·web·javaee
hope_wisdom1 小时前
C/C++数据结构之栈基础
c语言·数据结构·c++··stack
B612 little star king1 小时前
力扣29. 两数相除题解
java·算法·leetcode
野犬寒鸦1 小时前
力扣hot100:环形链表(快慢指针法)(141)
java·数据结构·算法·leetcode·面试·职场和发展
时光追逐者1 小时前
C# 哈希查找算法实操
算法·c#·哈希算法