希尔排序

希尔排序(Shell Sort)是插入排序的一种,


是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。


希尔排序是基于插入排序的以下两点性质而提出改进方法的:
  1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
  2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

希尔排序法的基本思想是:

      先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

       一般的初次取序列的一半为增量,以后每次减半,直到增量为1。

       各组内的排序通常采用直接插入法。由于开始时s的取值较大,每组内记录数较少,所以排序比较快。随着不断增大,每组内的记录数逐步增多,但由于已经按排好序,因此排序速度也比较快。

稳定性:

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


对于n个元素的数组,假设增量为 h:

第一趟  :  从第1个元素开始,每隔h取一个元素,那么最后可以得到n/h个元素,一边取,一边通过直接插入将这h个元素排序
第二趟  :  从第2个元素开始,每隔h取一个元素,跟第一趟一样。  
...
第h趟   :  从第h个元素开始,每隔h取一个元素,跟第一趟一样。

(此时,整个数组还不是有序的)

然后,减少h的值,重复上面的操作,直到h减小为1,排序完成。

时间复杂度

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

import java.util.Arrays;
//希尔排序
public class ShellSort 
{
	public static void main(String[] args) 
	{
		int[] arr= new int[]{800,9,3,6,12,54,35,411,3,245,1,0,4};
		System.out.println("排序前:");
		System.out.println(Arrays.toString(arr));

		shellSort(arr);
		
		System.out.println("插入排序后:");
		for(int i=0; i<arr.length; i++)
		{
			if(i != arr.length-1)
				System.out.print(arr[i] + ",");
			else
				System.out.print(arr[i]);		
		}
	}

	public static void shellSort(int[] nums) {  

		int len = nums.length / 2;  

        while (len >=1) {  
			for (int i = 0; i < len; i++) {  
                // 直接插入排序对分组进行排序  
				for (int k = i; k < nums.length-len; k +=len) {  
                    int j = k + len;  
                    int temp = nums[j];  

                    while (k >= 0 && nums[k] > temp) {  
                        nums[j] = nums[k];  
                        k -= len;  
                        j -= len;  
                   }  
                    nums[j] = temp;  
                }  
            }  
            len = len/2;  
        }  

    }

}

/*程序输出:
排序前:
[800, 9, 3, 6, 12, 54, 35, 411, 3, 245, 1, 0, 4]
插入排序后:
0,1,3,3,4,6,9,12,35,54,245,411,800
*/


下面是一个更好理解的

/*
	希尔排序,其实相对于直接排序更高效的原因就是其减少了比较和交换的次数。
*/
public class ShellSort00 {

	public static void main(String[] args){

		int a[] = {1,54,6,3,78,34,12,45,56,100};
		int d = a.length;
		int temp = 0;

		while(true){
		   d /= 2;		   

		   for(int x = 0; x<d; x++){ //这层循环控制分完后的组数,确保每组都进行排序

			   for(int i = x+d; i<a.length;  i+=d){//接下来的两个for循环其实就是之前我们很熟悉的简单插入排序,
												//这里i的储值为x+d就是因为我们在直接插入排序的时候外层循环要从第二个元素开始				  
				  temp = a[i];

				  for(int j = i-d;; j>=0 && temp<a[j]; j-=d){//这层控制插入的位置

					a[j+d] = a[j]; //把元素往后移动

				  }

				  a[j+d] = temp;

			   }

		   }

		   if(d == 1)
			   break;
		}

		for(int i=0; i<a.length; i++)

		   System.out.print(a[i] + " ");  //输出:1 3 6 12 34 45 54 56 78 100

	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值