希尔排序

声明:
主要代码和部分算法说明参考自算法(第四版),这里将代码列出,是想和大家交流一些学习心得。

1.简介

希尔排序建立在插入排序的基础上,不同的是,希尔排序交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

2.思路

如果现在有个大小为16的整形数组:
Integer[] a = {16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
首先我们会根据数组长度算出一个合适的步长(用h表示)。

int h = 1; //给步长h一个初始值
while(h<N/3) h=3*h+1; //1,4,13...赋予h一个合适的步长

经过计算,可以得到长度为16的数组的步长是13。
然后进行排序,分别会使a[13]和a[13-13]有序(默认升序):
Integer[] a = {3,15,14,13,12,11,10,9,8,7,6,5,4,16,2,1};
a[14]和a[14-13]有序:
Integer[] a = {3,2,14,13,12,11,10,9,8,7,6,5,4,16,15,1};
a[15]和a[15-13]有序:
Integer[] a = {3,2,1,13,12,11,10,9,8,7,6,5,4,16,15,14};
上面得到的数组就是一个步长为13的有序数组。

接着我们继续减小步长:

h = h/3;

现在的h是4,按照之前的方法再继续进行步长为4的排序。
即对(a[4]和a[0])、(a[5]和a[1])、(a[6]和a[2])、(a[7]和a[3])、(a[8]和a[4],a[4]和a[0])、(a[9]和a[5],a[5]和a[1])……进行排序。

最后,当h减小到1时,则变成了一个插入排序,但是不同的是,此时的数组已经是基本有序的了,之前的数组会变成:
3 2 1 5 4 7 6 9 8 11 10 13 12 16 15 14
虽然不是绝对的有序,但是已经基本有序,而这时再进行插入排序,效率就会高很多了。

3.代码

排序代码(核心):

public class Shell {
    //升序排序
    public static void sort(Comparable[] a){
        int N = a.length;
        int h = 1; //给步长h一个初始值
        while(h<N/3) h=3*h+1; //1,4,13...赋予h一个合适的步长
        while(h>=1){ //h最小值为1,h=1时,变成插入排序
            for(int i=h; i<N; i++){ //将数组变为h有序数组
                //将a[i]插入到a[i-h],a[i-2h]a[i-3h]...之中
                for(int j=i; j>=h && Example.less(a[j], a[j-h]); j-=h)
                    Example.exch(a, j, j-h);
            }
            h = h/3;
        }
    }
}

其余代码(测试):

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;

//p153  排序算法类的模板
public class Example {

    //对数组中的元素(实现了Comparable接口)进行排序
    public static void sort(Comparable[] a){
//      //选择排序
//      Selection.sort(a);

//      //插入排序
//      Insertion.sort(a);

        //希尔排序
        Shell.sort(a);
    }

    //判断v是否小于w
    public static boolean less(Comparable v,Comparable w){
        //如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数
        return v.compareTo(w) < 0;
    }

    //交换两个元素的位置
    public static void exch(Comparable[] a, int i, int j){
        Comparable t = a[i]; a[i] = a[j]; a[j] = t;
    }

    //打印数组
    public static void show(Comparable[] a){
        for(int i = 0; i<a.length; i++)
            StdOut.print(a[i]+" ");
        StdOut.println();
    } 

    //判断数组a是否有序
    public static boolean isSorted(Comparable[] a){
        for(int i=1; i<a.length; i++){
            if( less(a[i],a[i-1]) ) {
                return false; //因为默认升序排列
            }
            //System.out.println("判断是否有序中:"+a[i-1]+"小于"+a[i]);
        }
        return true;
    }

    //测试
    public static void main(String[] args) {
        //@SuppressWarnings("deprecation")
        //String[] a = In.readStrings();
        Integer[] a = {16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; 
        sort(a);
        if(isSorted(a)) System.out.println("有序");
        show(a);
    }

}

运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

注:
上面一定要建立Integer数组,而不是String数组,因为数字和字符串判断大小的依据不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴瘦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值