算法系列(五):希尔排序

188 阅读3分钟

希尔排序介绍:

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序(n-增量排序),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止

希尔排序的过程:

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 dt=1(dt <dt-1 …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

该方法实质上是一种分组插入方法 比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。 一般的初次取序列的一半为增量,以后每次减半,直到增量为1。 给定实例的shell排序的排序过程 假设待排序文件有10个记录,其关键字分别是: 49,38,65,97,76,13,27,49,55,04。 增量序列的取值依次为: 5,2,1 ##希尔排序代码如下:

package com.nineweeks.simplesort;

/**
 * 希尔排序
 *
 *  解决插入排序时,复制次数过多的问题,插入排序是时,左边的子数组是有序的
 * ,将右边的第一个无序元素放在临时变量中,拿它依次和左边的数组元素进行比较,
 * 在合适的地方进行插入,此时平均需要移动n/2次,那个数据需要移动n2/2,这也就是
 * 为什么插入排序的时间复杂度为O(n2)
 *
 * 希尔排序在中大规模的数组排序时,效率并没有快速排序或者并归排序这些时间复杂度
 * O(nlgn)快,但是比O(n2)还是要快,而且他的最坏情况和平均情况差别不大
 *
 * 我们提倡在任务排序工作之前先用shell排序,如果证明他不够快,在用其他高级算法
 *
 *  希尔排序 也叫作 n-增量排序
 * @author NineWeek
 * @date 2020/05/07 17:20
 **/
public class ShellSort {
    private long[] array;
    private int nElems;

    public ShellSort(int max){
        this.array = new long[max];
        this.nElems = 0;
    }

    public void insert(long value){
        array[nElems++] = value;
    }

    /**
     * 数组的展示方法
     */
    public void display(){
        for (int i = 0; i < nElems ; i++) {
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }

    public void sort(){
        int inner,outer;
        long temp;

        int h=1;
        while(h<=nElems/3){ //找到初始的增量值(最大增量值)
            h=h*3+1;
        }

        while(h>0){
            //控制外层循环(例如nElems = 160,增量区间依次为) 121 40 13 4 1
            for(outer = h;outer<nElems;outer++){
                temp = array[outer];
                inner = outer;
                while (inner>h-1 && array[inner-h]>=temp){
                    array[inner] = array[inner-h];
                    inner-=h;
                }
                array[inner] = temp;
            }
            h=(h-1)/3;
        }
    }

    public static void main(String[] args){
        int max = 10;
        ShellSort shellSort = new ShellSort(max);

        for(int j=0;j<max;j++){
            long  n = (int)(Math.random()*99);
            shellSort.insert(n);
        }

        shellSort.display();

        shellSort.sort();

        shellSort.display();
    }
}

输出结果: