希尔排序增量研究
上一篇介绍了希尔排序,它又被称为缩小增量排序,这就说明了增量在希尔排序中的重要性。
本篇使用四组不同的增量,通过统计排序的比较次数、移动次数、执行时间,来讨论不同的增量对希尔排序效率的影响。
选取的增量:h1=N/2, N/4, N/8,……,1(每次增量减半)
h2=N/3, N/9, N/27,……,1(每次增量为原来的三分之一)
h3=2ⁿ-1 (h=1,3,7,……)(增量为奇数)
h4=(3ⁿ-1)/2 (h=1,4,13,……)
1、保持序列元素个数不变
保持序列元素个数为1000000,每次随机生成不同的序列,对四个增量分别做4组排序。
增量h | 比较次数 | 移动次数 | 执行时间(ms) | 平均时间(ms) |
h1 | 70899317 | 53401514 | 390 | 409 |
71248646 | 53751082 | 437 | ||
63125216 | 45628028 | 406 | ||
65709200 | 48211399 | 406 | ||
h2 | 58908538 | 47827463 | 328 | 367 |
57271566 | 46192005 | 360 | ||
58745050 | 47664214 | 422 | ||
58158118 | 47077871 | 359 | ||
h3 | 63337835 | 45942623 | 391 | 434 |
62261484 | 44866301 | 422 | ||
64507400 | 47112762 | 485 | ||
65932139 | 48537533 | 438 | ||
h4 | 67600938 | 56206667 | 359 | 398 |
62428374 | 51034112 | 390 | ||
67867685 | 56472626 | 453 | ||
63794589 | 52400141 | 391 |
从测试的结果来看,当序列元素个数相同时,对四种增量分别用生成的四组随机数排序时,它们的比较次数、移动次数以及执行时间等参数差别不大。因此可以认为对于待排序列的元素个数相同的情况下,基于以上四种增量的序列,希尔排序算法的时间复杂度差异不是很明显,执行效率差别不大。
2、序列的元素个数改变
使序列元素个数增加,分别取10000、100000、1000000、10000000,每次随机生成不同的序列,对四个增量分别排序。
元素个数 | 增量h | 比较次数 | 移动次数 | 执行时间(ms) |
10000 | h1 | 266301 | 151388 | 0 |
h2 | 242150 | 171389 | 0 | |
h3 | 237881 | 129346 | 15 | |
h4 | 238686 | 167816 | 0 | |
100000 | h1 | 4270009 | 2820476 | 32 |
h2 | 4174584 | 3267076 | 15 | |
h3 | 3959590 | 2543037 | 32 | |
h4 | 3867292 | 2941534 | 31 | |
1000000 | h1 | 66890878 | 49393622 | 422 |
h2 | 59190877 | 48110274 | 360 | |
h3 | 59872906 | 42478486 | 406 | |
h4 | 62805422 | 51410564 | 375 | |
10000000 | h1 | 1035250229 | 820261049 | 5301 |
h2 | 1167560154 | 1036812889 | 5532 | |
h3 | 980127157 | 772150177 | 5294 | |
h4 | 9659604955 | 854508598 | 5378 |
从测试结果可以看出,不同长度的序列使用四个增量分别进行排序时,比较次数、移动次数、排序时长有一定差异。当元素个数较少时,增量为h2=N/3, N/9, N/27,……,1的希尔排序效率比其他增量略高;
当元素个数较多时,增量为h4=(3ⁿ-1)/2 (h=1,4,13,……)的希尔排序效率比其他增量略高。
综上所述,希尔排序算法在不同增量下的执行效率也不尽相同,增量是影响希尔排序效率的重要因素。遗憾的是,虽然有很多论文专门研究过不同的增量对希尔排序的影响,但都无法证明某个增量是最好的。因此在使用希尔排序时,根据排序序列的大小,选取适当的增量对提高排序效率很有帮助。
参考代码:以Java为例。
import java.util.Random; /* * 希尔排序 */ public class ShellSort { //增量h=N/2 static long comp1 = 0; //比较次数 static long exch1 = 0; //交换次数 public static void sort1(int[] a) { int n = a.length; //序列长度 int h = n/2; //初始增量h为序列长度的一半 while (h >= 1) { for (int i = h; i < n; i++) { for (int j = i; j >= h; j -= h) { comp1++; if(a[j]<a[j-h]){ int swap = a[j]; a[j] = a[j-h]; a[j-h] = swap; exch1++; }else{ break; } } } h /= 2; //增量减半 } } //增量h=N/3 static long comp2 = 0; //比较次数 static long exch2 = 0; //交换次数 public static void sort2(int[] a) { int n = a.length; //序列长度 int h = n/3; //初始增量h为序列长度的三分之一 while (h >= 1) { for (int i = h; i < n; i++) { for (int j = i; j >= h; j -= h) { comp2++; if(a[j]<a[j-h]){ int swap = a[j]; a[j] = a[j-h]; a[j-h] = swap; exch2++; }else{ break; } } } h /= 3; //增量减为三分之一 } } //增量h=2ⁿ-1 (h=1,3,7……) static long comp3 = 0; //比较次数 static long exch3 = 0; //交换次数 public static void sort3(int[] a) { int n = a.length; //序列长度 int h = 1; while (h < n/2) h = 2*h + 1; while (h >= 1) { for (int i = h; i < n; i++) { for (int j = i; j >= h; j -= h) { comp3++; if(a[j]<a[j-h]){ int swap = a[j]; a[j] = a[j-h]; a[j-h] = swap; exch3++; }else{ break; } } } h /= 2; } } //增量h=(3ⁿ-1)/2 (h=1,4,13……) static long comp4 = 0; //比较次数 static long exch4 = 0; //交换次数 public static void sort4(int[] a) { int n = a.length; //序列长度 int h = 1; while (h < n/3) h = 3*h + 1; while (h >= 1) { for (int i = h; i < n; i++) { for (int j = i; j >= h; j -= h) { comp4++; if(a[j]<a[j-h]){ int swap = a[j]; a[j] = a[j-h]; a[j-h] = swap; exch4++; }else{ break; } } } h /= 3; } } public static void main(String[] args) { Random random = new Random(); int[] arg = new int[10000]; for(int n=0;n<10000;n++){ //从[0-10000]中生成10000个随机数 arg[n] = random.nextInt(10000); } int[] arg1 = new int[arg.length]; int[] arg2 = new int[arg.length]; int[] arg3 = new int[arg.length]; int[] arg4 = new int[arg.length]; for(int n=0;n<arg.length;n++){ //将随机生成的数组复制到4个数组中 arg1[n] = arg[n]; arg2[n] = arg[n]; arg3[n] = arg[n]; arg4[n] = arg[n]; } //分别对4个元素相等的数组用4个不同增量排序 long startTime1 = System.currentTimeMillis(); //获取开始时间 sort1(arg1); long endTime1 = System.currentTimeMillis(); //获取结束时间 long startTime2 = System.currentTimeMillis(); //获取开始时间 sort2(arg2); long endTime2 = System.currentTimeMillis(); //获取结束时间 long startTime3 = System.currentTimeMillis(); //获取开始时间 sort3(arg3); long endTime3 = System.currentTimeMillis(); //获取结束时间 long startTime4 = System.currentTimeMillis(); //获取开始时间 sort4(arg4); long endTime4 = System.currentTimeMillis(); //获取结束时间 System.out.println("数组长度:"+arg.length); System.out.println("增量h=N/2的比较次数: "+comp1+" 交换次数:"+exch1+" 排序时长:"+(endTime1-startTime1)+"ms"); System.out.println("增量h=N/3的比较次数: "+comp2+" 交换次数:"+exch2+" 排序时长:"+(endTime2-startTime2)+"ms"); System.out.println("增量h=2ⁿ-1的比较次数: "+comp3+" 交换次数:"+exch3+" 排序时长:"+(endTime3-startTime3)+"ms"); System.out.println("增量h=(3ⁿ-1)/2的比较次数:"+comp4+" 交换次数:"+exch4+" 排序时长:"+(endTime4-startTime4)+"ms"); } }
执行结果:
数组长度:10000 增量h=N/2的比较次数: 265465 交换次数:150579 排序时长:0ms 增量h=N/3的比较次数: 230360 交换次数:159712 排序时长:0ms 增量h=2ⁿ-1的比较次数: 238035 交换次数:129679 排序时长:15ms 增量h=(3ⁿ-1)/2的比较次数:227429 交换次数:156614 排序时长:0ms
转载请注明出处 http://www.cnblogs.com/Y-oung/p/7805984.html
工作、学习、交流或有任何疑问,请联系邮箱:yy1340128046@163.com