今天在看韩顺平老师的希尔排序算法时,老师提到希尔排序有两种方式:移位法和交换法。
由于希尔排序是为了优化插入排序,但是老师在演示时,在排列80000条数据时,插入排序大约耗时5S,而移位法的希尔排序耗时约17S,交换法的希尔排序用时约1S。为什么会出现这么大差别呢?
经过观察思考,发现移位法比交换法多了很多多余的步骤,那就是不断变化数值。
两种方法的输出结果一样且正确,但是执行效率差别很大。以数组int[] arr = {8,9,1,7,2,3,5,4,6,0};为例, 两种方法的第一次分组操作基本相同,移位法在执行第二次分组操作时,此时间隔为5/2=2,第一轮,元素下标从2也就是第三个元素数字1开始,比较前面间隔为2的元素数字3,发现3比1大,因此发生直接移位;第二轮5<6所以不发生位移;第三轮,3>0,3和0移位,即此时数组的数据是[1, 5, 0, 6, 3, 8, 9, 4, 7, 2],根据循环再次和0前面的1比较1>0,所以1和0移位,此时[0, 5, 1, 6, 3, 8, 9, 4, 7, 2],由此可见,中间借助temp移动了两次,这个过程在数据量大的情况下非常消耗时间。
对于交换法来说,同样是在这个位置,它的处理方法就比移位法灵活很多,首先它定义int temp = arr[j](此时j的值为4);即将此时结果存到temp中,然后直接与前面进行比较:3>0满足条件,将原本0的位置上的数字改成3,即此时数据是[1, 5, 3, 6, 3, 8, 9, 4, 7, 2],**继续循环,发现1和0比(注意此时循环判断条件不是判断3和1,而是判断temp和1,此时temp的值依然是0),1>0满足条件,因此将原本是3的位置上元素改成1,即[1, 5, 1, 6, 3, 8, 9, 4, 7, 2],回到循环,由于循环条件不满足,直接执行下一步,把temp的值赋给arr[j](此时j已经为0)**,此时[0, 5, 1, 6, 3, 8, 9, 4, 7, 2]。这个过程的元素temp只移动了一次。后面的过程与前面类似我不在赘述。
总结:算法的魅力在于能把复杂的问题变得简单,而在程序中,虽然基本思想都是一样的,但是如果在算法中不合理去运用技巧,也可能“弄巧成拙”,这个例子就能说明了这一点。
如果有什么错误的地方,还请各位批评指正,笔者在此谢谢大家的阅读。
代码:
public static void shellSort3(int[] arr) {
int count = 1;
int count2 = 1;
for(int gap = arr.length/2;gap>0;gap/=2) {
System.out.println("第"+count+"次分组前数组信息"+Arrays.toString(arr));
System.out.println("第"+count+"次分组开始");
for(int i=gap;i<arr.length;i++