五十道编程小题目 --- 28 八大排序算法 java 之 02希尔排序

 2. 插入排序—希尔排序(Shell`s Sort)

希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。希尔排序又叫缩小增量排序

基本思想:

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

操作方法:

  1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  2. 按增量序列个数k,对序列进行k 趟排序;
  3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

希尔排序的示例:


算法实现:

 

我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n为要排序数的个数

即:先将要排序的一组记录按某个增量dn/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. import java.util.Random;  
  2.   
  3. public class ShellSort {  
  4.       
  5.     //希尔排序  
  6.     public static int[] shellSort(int[] arr){  
  7.   
  8.         /*//确定增量序列 
  9.         double n = arr.length; 
  10.         int[] d = new int[(int)n];   //增量序列 
  11.          
  12.         for(int i=0; i<n; i++){ 
  13.             if(n > 0){ 
  14.                 d[i] = (int) Math.ceil(n/2); 
  15.                 n = (int) Math.ceil(n/2); 
  16.                 if( n <= 3 ){ 
  17.                     d[i+1] = 1; 
  18.                     break; 
  19.                 } 
  20.             } 
  21.         } 
  22.         System.out.println("增量序列:"); 
  23.         print(d);*/  
  24.           
  25.           
  26.         double n = arr.length;  //n 定义为double很重要。如果是int ,这(int)Math.ceil(5/2)==2。如果是double,(int)Math.ceil(5/2)==3  
  27.           
  28.         for(int i=(int)Math.ceil(n/2) ; i>0 ; i=(int)Math.ceil(n/2) ){  //增量序列:  
  29.               
  30.             if( i==2 && n%2 != 0){ //如果是n=5时,下一个增量应该是3,在下一个增量应该是1,去除2,  
  31.                 n=i;               //但是, 如果是n=4时,下一个增量应该是2, 此时增量为2 ,应该被保留     
  32.                 continue;  
  33.             }  
  34.               
  35.             for(int j=0; j<n ;j++ ){  //趟数,趟数与增量相同  
  36.                 int k = j;  
  37.                 while(k+i<arr.length){  //分组,将arr 分组为相隔i的几组,然后一个一个比较  
  38.                     if ( arr[k] > arr[k + i]) {  
  39.                         int tmp = arr[k];  
  40.                         arr[k] = arr[k + i];  
  41.                         arr[k + i] = tmp;  
  42.                     }  
  43.                     k = k+i;  
  44.                 }  
  45.             }  
  46.             n = i;  
  47.               
  48.             System.out.print("增量为" + i + "时,排序为  :  ");  
  49.             print(arr);  
  50.               
  51.             if(n==1){  // 因为double n=1,时   (int)Math.ceil(n/2)==1,如果不写break,这里会一直循环  
  52.                 break;  
  53.             }  
  54.               
  55.         }  
  56.           
  57.         return arr;  
  58.     }  
  59.       
  60.     // 打印数组  
  61.     public static void print(int[] arr) {  
  62.         for (int i = 0; i < arr.length; i++) {  
  63.             System.out.print(arr[i] + " ");  
  64.         }  
  65.         System.out.println();  
  66.     }  
  67.   
  68.     public static void main(String[] args) {  
  69.           
  70.         int[] arr2 = {49,38,65,97,76,13,27,49,55,04};  
  71.           
  72.         System.out.println("排序前  : ");  
  73.         print(arr2);  
  74.         System.out.println("排序后  : ");  
  75.         print(shellSort(arr2));  
  76.           
  77.           
  78.         //测试:  
  79.         System.out.println();  
  80.         System.out.println("任意数组测试:");  
  81.         Random r = new Random();  
  82.         int[] testArr = new int[20];  
  83.         for (int i = 0; i < 20; i++) {  
  84.             testArr[i] = r.nextInt(100);  
  85.         }  
  86.           
  87.         System.out.println("排序前  : ");  
  88.         print(testArr);  
  89.         System.out.println("排序后  : ");  
  90.         print(shellSort(testArr));  
  91.   
  92.     }  
  93.       
  94. }  
  95.       
  96.       

输出结果:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. 排序前  :   
  2. 49 38 65 97 76 13 27 49 55 4   
  3. 排序后  :   
  4. 增量为5时,排序为  :  13 27 49 55 4 49 38 65 97 76   
  5. 增量为3时,排序为  :  13 4 49 38 27 49 55 65 97 76   
  6. 增量为1时,排序为  :  4 13 27 38 49 49 55 65 76 97   
  7. 4 13 27 38 49 49 55 65 76 97   
  8.   
  9. 任意数组测试:  
  10. 排序前  :   
  11. 38 57 9 30 49 27 45 83 88 76 14 53 16 58 77 21 20 40 55 94   
  12. 排序后  :   
  13. 增量为10时,排序为  :  14 53 9 30 49 21 20 40 55 76 38 57 16 58 77 27 45 83 88 94   
  14. 增量为5时,排序为  :  14 20 9 30 49 21 45 16 55 76 27 53 40 58 77 38 57 83 88 94   
  15. 增量为3时,排序为  :  14 20 9 30 16 21 40 27 53 38 49 55 45 57 77 76 58 83 88 94   
  16. 增量为1时,排序为  :  14 9 16 20 21 27 30 38 40 49 45 53 55 57 58 76 77 83 88 94   
  17. 14 9 16 20 21 27 30 38 40 49 45 53 55 57 58 76 77 83 88 94   


希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。目前还没有人给出选取最好的 增量因子序列的方法。 增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意: 增量因子中除1 外没有公因子,且最后一个 增量因子必须为1。希尔排序方法是一个 不稳定的排序方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值