算法一小时--希尔排序

在写希尔排序之前,首先我对之前的Java代码进行了优化。

之前的代码中由于Comparable<T>中的T都是用的String,因此在写一个测试方法时,必须对输入的数字进行转换,十分麻烦。 因此我将方法都写成了泛型的写法:

package com.jacob.demo;

/**
 * This is a sample for sort algorithms.
 * @author jacob
 *
 */
public class Example {
    
    /**
     * The function for sort.
     * @param a
     */
    public static<T> void sort(Comparable<T>[] a) {
        
    }
    
    /**
     * Compare if v is less than w.
     * @param v
     * @param w
     * @return
     */
    public static<T> boolean less(Comparable<T> v, Comparable<T> w) {
        return v.compareTo((T) w) < 0;
    }
    
    /**
     * exchange two elements.
     * @param a
     * @param i
     * @param j
     */
    public static<T> void exch(Comparable<T>[] a, int i, int j) {
        Comparable<T> t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    
    /**
     * Print array.
     * @param a
     */
    private static<T> void show(Comparable<T>[] a) {
        for (int i= 0; i< a.length; i++) {
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }
    
    /**
     * Judge if array is sorted
     * @param a
     * @return
     */
    public static<T> boolean isSorted(Comparable<T>[] a) {
        for (int i = 1; i < a.length; i++) {
            if (less(a[i], a[i-1])) {
                return false;
            }
        }
        
        return true;
    }
    
    public static void main(String[] args) {
        String[] a = {"S","O","R","T","E","X","A","M","P","L","E"};
        System.out.println("Before sort:");
        show(a);
        
        System.out.println("sort begin:");
        sort(a);
        assert isSorted(a);
    }
}

 

之后的代码也会采用该模板。

言归正传。

1. 希尔排序的实现思路

希尔排序是基于插入排序改进出来的一种排序方法。 对于插入排序来说,当遇到大规模乱序数组的时候,速度是比较慢的,因为它只会交换相邻的元素,因此元素只能一个一个从数组一端移动到另一端,上一篇的例子中是从末尾移动到对应的位置。

希尔排序为了加快速度,改进了插入排序。它将数组根据间隔元素数h分成了几个小数组,然后对这些小数组进行局部插入排序,然后递减h,最终将这些全部排序。

例如:

Before sort:

S H E L L S O R T E X A M P L E         //初始数组

sort begin:

//第一次分组,间隔h取13

[P] [H] [E] [L] L S O R T E X A [M] [S] [L] [E]   //第一次排序结束

a loop is over; h is 13

// 第二次分组,h 取 4

[L] H E L [P] S O R [T] E X A [M] S L E      // 对 P L T M 进行插入排序

[L] H E L [P] S O R [T] E X A [M] S L E       

[L] H E L [P] S O R [T] E X A [M] S L E     

[L] H E L [P] S O R [T] E X A [M] S L E    

[L] H E L [P] S O R [T] E X A [M] S L E      

L [E] E L P [H] O R T [S] X A M [S] L E    // 对 H S E S 进行插入排序

L [E] E L P [H] O R T [S] X A M [S] L E 

L [E] E A P [H] O L T [S] X R M [S] L E 

L [E] E A M [H] O L P [S] X R T [S] L E 

L E [E] A M H [O] L P S [X] R T S [L] E      //对E O X L j进行插入排序

L E [E] A M H [L] L P S [O] R T S [X] E 

L E E [A] M H E [P] S O L [T] S X R          //对A P T 进行插入排序 

 

// 第三次分组,h取1, 此时就是对数组进行一次插入排序

E L E A M H L E P S O L T S X R 

E E L A M H L E P S O L T S X R 

A E E L M H L E P S O L T S X R 

A E E L M H L E P S O L T S X R 

A E E H L M L E P S O L T S X R 

A E E H L L M E P S O L T S X R 

A E E E H L L M P S O L T S X R 

A E E E H L L M P S O L T S X R 

A E E E H L L M P S O L T S X R 

A E E E H L L M O P S L T S X R 

A E E E H L L L M O P S T S X R 

A E E E H L L L M O P S T S X R 

A E E E H L L L M O P S S T X R 

A E E E H L L L M O P S S T X R 

A E E E H L L L M O P R S S T X 

//排序结束

 

根据上述的希尔排序的实现思路,实现代码如下:

 

/**
     * The function for sort.
     * @param a
     */
    public static<T> void sort(Comparable<T>[] a) {
        int h = 1;
        int N = a.length;
        
        while(h < N/3) {
            h = 3*h + 1;
        }
        
        while(h >=1) {
            for(int i = h; i < N; i++) {
                for(int j= i; j >= h && less(a[j], a[j-h]); j-=h) {
                    exch(a, j, j-h);
                }
                show(a);
            }
            
            System.out.println("a loop is over; h is " + h);
            h=h/3;
        }
    }

希尔排序更高效的原因是它权衡了子数组的规模和有序性。

另外,选择h也是一个难点,一般取决于其数学性质,如公因子等。

 

JS的实现

根据希尔排序的实现原理,JS的实现代码如下:

function shell(array) {

    let h = 1;

    // splite array to serveral arraies with h elements.
    while(h < array.length / 3) {
        h = 3*h +1;
    }

    // insertion for h elements array.
    while(h >= 1) {
        for(i = h; i < array.length; i++) {
            for(j = i; j >= h && array[j] < array[j-h]; j-=h ) {
                exch(array, j-h, j);
            }
            console.log(array);
        }
        console.log("a loop is done, h is " + h);
        h=parseInt(h/3);
        
    }

}

function exch(array, firstIndex, minIndex) {
    let temp = array[firstIndex];
    array[firstIndex] = array[minIndex];
    array[minIndex] = temp;
}

function main() {
    var arr = [5,3,7,1,7,8,1];
    console.log(arr);
    shell(arr);
    console.log("after sort");
    console.log(arr);
}

main();

 

转载于:https://www.cnblogs.com/JacobQiao/p/9378681.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值