希尔排序

2018-02-02  本文已影响5人  Stroman
package com.company;

public class ShellSort {
    /**
     * 希尔排序其实是插入排序的变种
     * 在这里姑且先用非递归排序实现
     * 此算法
     * 只不过它有步长的设定
     * 即,根据步长来对整个数组进行分组
     * 不过每个分组中的元素都是间距相同
     * 的两个元素
     * 然后对每组进行排序
     * 其实也是分而治之算法的体现
     * @param sourceArray
     */
    static public void shellSort0(int[] sourceArray) {
        int arrayLength = sourceArray.length;
        //一开始的步长。
        int stepWidth = arrayLength;
        //因为最后的步长肯定会变成1的
        //这也就意味着最后一次排序的进行了
        while (stepWidth > 1) {
            //姑且把步长设置为原来步长的1/2吧
            stepWidth /= 2;
            //打印
            System.out.println("步长为" + stepWidth);
            //我之所以这样写是因为我觉得
            //1、步长会越来越小
            //2、所有步长相邻的元素都可以从开始
            //被遍历到。
            //但是这样写会使整个实现变得很长
            for (int counter = 0;counter < stepWidth;counter++) {
                //现在开始进行一小趟的排序
                //通过插入排序法对每个元素进行排序
                //需要被插入的index
                int stepIndex = 1;
                //这个元素的index不能超出数组范围
                while (counter + stepIndex * stepWidth < arrayLength) {
                    int insertIndex = counter + stepIndex * stepWidth;
                    //先保存这个待插入的元素值
                    int tempElement = sourceArray[insertIndex];
                    //元素该插入的位置。
                    int targetIndex = counter;
                    for (int counter0 = counter;counter0 < counter + stepIndex * stepWidth;counter0+=stepWidth) {
                        if (tempElement > sourceArray[counter0]) {
                            targetIndex = counter0;
                            //移动元素
                            for (int counter1 = insertIndex;counter1 > targetIndex;counter1-=stepWidth)
                                sourceArray[counter1] = sourceArray[counter1 - stepWidth];
                            //插入元素
                            sourceArray[targetIndex] = tempElement;
                            break;
                        } else continue;
                    }
                    //打印每一分组的元素状况。
                    for (int element:sourceArray) {
                        System.out.print(element + " ");
                    }
                    System.out.println("第" + stepIndex + "次交换结束了");
                    stepIndex++;
                }
                //打印每一趟的元素状况。
                for (int element:sourceArray) {
                    System.out.print(element + " ");
                }
                System.out.println("第" + (counter + 1) + "趟结束了\n");
            }
        }
    }

    /**
     * 上面的方法写得过于冗长
     * 本方法是参照了网上的版本
     * 把代码写得精简了一些
     * @param sourceArray
     */
    static public void shellSort1(int[] sourceArray) {
        int arrayLength = sourceArray.length;
        //上面那个while循环完全可以写成for循环
        for (int stepWidth = arrayLength / 2;stepWidth >= 1;stepWidth /= 2){
            //因为上面的方法比较长,所以此处需要改写。
            //毕竟插入排序算法是从第2个元素开始的
            //其实就相当于步长为1了
            //而现在是步长是大于了
            //那么就是说可以从1*stepWidth开始
            //下面这样写是把插入和遍历整个数组的思想结合起来了
            //这种写法的宏观着眼点是针对每个元素采取不同的方式来处理
            //我上面的着眼点是一个个单独的相邻步长的元素
            //我上面的写法总是直接切入没拐弯
            for (int counter = stepWidth;counter < arrayLength;counter++) {
                //这个还是保存需要被插入的元素值
                int tempElement = sourceArray[counter];
                //这样就把下标变成从0开始了
                int counter0 = counter - stepWidth;
                //它是从后往前遍历,只要不满足这个条件就代表找到位置了
                //而我是从前往后正向遍历——很麻烦!
                //从后往前写给人的感觉思路非常清晰
                //并且这样遍历到每个元素,它之前的元素
                //都已经是排好序的了
                while (counter0 >= 0 && tempElement > sourceArray[counter0]) {
                    sourceArray[counter0 + stepWidth] = sourceArray[counter0];
                    counter0 -= stepWidth;
                }
                sourceArray[counter0 + stepWidth] = tempElement;
            }
            //打印每一趟的元素状况。
            for (int element:sourceArray) {
                System.out.print(element + " ");
            }
            System.out.println("步长 " + stepWidth + " 的趟结束了\n");
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读