回首Java——希尔排序(最小增量排序)

来源:互联网 发布:html5网购商城源码 编辑:程序博客网 时间:2024/05/22 02:00

什么是希尔排序

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。


原理

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。


基本思想

算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

该方法实质上是一种分组插入方法


稳定性

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。


算法分析

优劣

不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O( ),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。
但是比O( )复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。

时间性能

1.增量序列的选择
Shell排序的执行时间依赖于增量序列。
好的增量序列的共同特征:
① 最后一个增量必须为1;
② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。

2.Shell排序的时间性能优于直接插入排序

希尔排序的时间性能优于直接插入排序的原因:
①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
②当n值较小时,n和 的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0( )差别不大。
③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
因此,希尔排序在效率上较直接插入排序有较大的改进。


希尔分析

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。

希尔排序的示例:

image

第一趟排序从2/n=5 间隔内排序

第二趟排序从2/5=3 间隔内排序(取奇数,因为用非质数对整体的排序效果更好)
依此类推,最后到1进行直接插入排序,由于每次间隔内的排序后,对之前的排序结果并没有影响,这是减少了逆序对的方式,最后用直接插入排序排序的方式,是插入排序的加强。


算法实现:

public class ShellSort {    public static void main(String[] args) {        int[] arr = { 57, 68, 59,52,72, 28, 96, 33, 24, 19 };        shellSort(arr);    }    private static void shellSort(int arr[]) {        int j = 0;        int temp = 0;        /**         * 每次都以n/2的间隔分割序列,直到为1为止,在这里第一次分割为5,第二次为2,第三次为1         * 注意:2是一个质数,这里并没有特殊处理         */        for (int increment = (arr.length / 2); increment > 0; increment /= 2) {            for (int i = increment; i < arr.length; i++) {// 插入排序                temp = arr[i];                for (j = i; j >= increment; j -= increment) {                    if (temp < arr[j - increment]) {// 如想从小到大排只需修改这里                        arr[j] = arr[j - increment];// 将大于temp的值整体后移一个间隔单位                    } else {                        break;                    }                }                arr[j] = temp;//// 新元素落位            }        }    }}
阅读全文
0 0
原创粉丝点击