希尔排序详解Java

刚接触希尔排序的时候,我是懵的,因为在学校根本没有学过希尔排序啊!

查询资料:希尔排序是插入排序的升级版;

从维基百科截取的Java实现希尔排序的代码

public static void shellSort(int[] arr) {
        int length = arr.length;
        int temp;
        for (int step = length / 2; step >= 1; step /= 2) {
            for (int i = step; i < length; i++) {
                temp = arr[i];
                int j = i - step;
                while (j >= 0 && arr[j] > temp) {
                    arr[j + step] = arr[j];
                    j -= step;
                }
                arr[j + step] = temp;
            }
        }
    }

我们来简单的试一下:

public class ShellSortFromWiki{
  public static void main(String[] args){
    int[] a = {4, 9, 11, 3, 8, 6, 2, 7, 13, 1, 12, 5, 10};
    shellSort(a);
    print(a);
  }

  public static void shellSort(int[] arr) {
        int length = arr.length;    //获取数组的长度
        int temp;                   //临时变量temp
        // step是每个区域的数值的个数,当每个区域排序到不能再继续往下排的时候;
        // 将区域再次变小,这里是 step /= 2,将每个区域再分一半 
        for (int step = length / 2; step >= 1; step /= 2) {
            for (int i = step; i < length; i++) {
                temp = arr[i];
                int j = i - step;
                while (j >= 0 && arr[j] > temp) {
                    arr[j + step] = arr[j];
                    j -= step;
                }
                arr[j + step] = temp;
            }
        }
    }
   
    static void print(int[] a){
      for (int i = 0; i < a.length; i++) {
        System.out.print(a[i] + " ");
      }
    }
}

打印:

对以上代码稍加修改,打印出每一次排序的过程

2 9 11 3 8 6 4 7 13 1 12 5 10
2 7 11 3 8 6 4 9 13 1 12 5 10
2 7 11 3 8 6 4 9 13 1 12 5 10
2 7 11 1 8 6 4 9 13 3 12 5 10
2 7 11 1 8 6 4 9 13 3 12 5 10
2 7 11 1 8 5 4 9 13 3 12 6 10
2 7 11 1 8 5 4 9 13 3 12 6 10
1 7 11 2 8 5 4 9 13 3 12 6 10
1 7 11 2 8 5 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 3 9 13 4 12 6 10
1 7 5 2 8 11 3 9 13 4 12 6 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 5 7 2 8 6 3 9 11 4 12 13 10
1 2 5 7 8 6 3 9 11 4 12 13 10
1 2 5 7 8 6 3 9 11 4 12 13 10
1 2 5 6 7 8 3 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 10 11 12 13
1 2 3 4 5 6 7 8 9 10 11 12 13

总共30行数据,减去最后一行打印,总共29条;

接下来说一下这个排序算法的排序方式:

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快).

注意:如果你看这些文字实在是看不懂,建议拿出纸笔,一步一步算(小编比较愚钝,就是这么做的);

这里维基百科提供的代码是根据数组的长度除以2[for (int step = length / 2; step >= 1; step /= 2)];

但这并不是最佳的解决方法

我们来比较一下相同的数组排序次数的差别:

插入排序:38次

二分希尔排序:29次

knuth希尔排序:21次

明显是knuth希尔排序更快,下面介绍一下knuth希尔排序算法:

public static void sort(int[] arr) {
		
		int h = 1;
		while(h <= arr.length /3 ) {
			h = h*3 + 1;
		}
		
		for(int gap = h; gap > 0; gap = (gap-1)/3) {

			for(int i=gap; i<arr.length; i++) {
				for(int j=i; j>gap-1; j-=gap) {
					if(arr[j] < arr[j-gap]) {
						swap(arr, j, j-gap);
					}
				}
			}
		}

	}

几种常见的Gap序列:

1)希尔原本的Gap:N/2、N/4、...1(反复除以2)
2)Hibbard的Gap:1、3、7、...、2k-1(k表示第几个gap)
3)Knuth的Gap: 1、4、13、...、(3k - 1) / 2(k表示第几个gap)
4)Sedgewick的Gap: 1、5、19、41、109、...

看不懂?!

拿出笔来算 !!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值