插入排序、希尔排序的Java实现

希尔排序也是一种插入排序,只不过是他的步长更大

插入排序属于内部排序,他的基本思想是把n个待排序的元素看成一个有序表、一个无序表,从无序表中挑选出元素,依次找到合适的位置插入有序表,直到无序表中的元素都插入到了有序表,n个元素变成了有序的。

插入排序、希尔排序的Java实现_第1张图片

从上面的动图我们可以看出,在比较的过程中有一个元素移动的过程,这个移动的步骤是我们代码的最内部动作。有序、无序数组的长度变化过程是通过一个for循环实现的,在寻找插入位置的过程是由一个for循环控制的,这两个for循环是嵌套的,内层的循环长度收外层for的影响,在两个for循环之内是有一个if的判断体,这个判断是用来判断是否找到了合适的元素,但是无论有没有找到合适的元素,我们元素的移动都是需要的。这是我们单纯的通过for实现的一个思路但是对于我们这种直到一个合适条件的判断题,是不是使用while的循环更加直接呢?使用while的时候我们通过while来实现对需要后移的元素进行后移,直到找到了一个合适的插入位置来跳出,首先需要后移的元素是要满足,前面的元素大于待插入的元素,并且索引不超出边界(insertIndex>=0&&insertVal)跳出了循环之后是不是找到了待插入的位置呢?如果待插入的元素本来就不需要进行移动呢?我们通过一个if(insertIndex+1!=i)来进行判断,判断条件产生是在合理位置的前一个元素,所以我们还应该对insertIndex+1,在进行赋值。

希尔排序就是把记录下标的一定增量分组,对魅族使用直接插入排序算法,随着增量的逐渐减少,每组的关键字越来越多,当增量减到1,这个文件便被分成了一组,我们实现一次插入排序,实现对元素的排序。希尔排序就是通过前面的大步长将需要很多步的元素尽快的移动到合适的位置,避免这样的情况出现:

插入排序、希尔排序的Java实现_第2张图片

 希尔排序的示意图:

插入排序、希尔排序的Java实现_第3张图片

 在初学的时候有很多人觉得希尔排序更像是冒泡排序的升级版,如果要是有这种想法的话,一定要再好好看看代码的实现,他确实是插入排序的一种实现思路而非冒泡!

 

两种排序算法的实现都可以有多种,for、while、递归,又有那种是更优雅的呢?

插入排序、希尔排序的Java实现_第4张图片

 这里通过while循环的实现感觉就是很巧妙,直接通过while循环实现所有应该后移的情况,再通过一个if来判断需要插入的情况。

在未排序的元素中挑选元素插入有序队列,不同的步长不同的实现方式,他们的运行性能又是怎么样的呢?

针对算法进行测试的一个代码样板,我们要做的就是把@FunctionName处改换为我们自己的名字:

    static final int arrSize = 80000;
    static long longStartTime = 0;
    static long longEndTime = 0;
    
    public static void main(String[] args) {
        System.out.println("测试数据开始生成-------------->");
        int arrSmall[] = {3, 9, -1, 10, -2};
        int arrBig[] = new int[arrSize];
        for (int i = 0; i < arrSize; i++) {
            arrBig[i] = (int) (Math.random() * arrSize); //生成一个[0, 8000000) 数
        }
        System.out.println("小数据量测试开始-------------->");
        @FunctionName(arrSmall);
        System.out.println("小数据量顺序测试:" + Arrays.toString(arrSmall));
    
        System.out.println();
    
        longStartTime = Calendar.getInstance().getTimeInMillis();
        System.out.println("大数量测试开始运行===========>");
        //测试冒泡排序
        @FunctionName(arrBig);
        longEndTime = Calendar.getInstance().getTimeInMillis();
        System.out.println(arrSize + "大数据量性能测试,花费的时间是:" + (longEndTime - longStartTime) / 1000 + "秒");
    }

 插入排序上述比较的两种代码实现:

//通过递归的方式实现,元素是从后面开始的
    public static void insertSortByWhile(int[] arr){
        //这里实现的思路是从后往前拍的,所以就可以直接通过while进行后移,相比for的操作
        //可以看成是省去了比较的步骤
        for (int i = 1; i < arr.length; i++) {
            int insertVal = arr[i];
            int insertIndex = i-1;
            //这个判断条件的设置很有技巧,
            while(insertIndex>=0&&insertVal= 0; j--) {
                if (arr[j] <= insertVal && j == i - 1) {
//                    System.out.println(insertVal+"前面是:"+arr[j]+"不用插入的数据");
                    break;
                } else {
//                    System.out.println(insertVal+"前面是:"+arr[j]+"需要插入的数据");
                    if (arr[j] < insertVal) {
//                        System.out.println("已经找到了待插入的位置:"+arr[j+1]+"要插入的是:"+insertVal);
                        arr[j + 1] = insertVal;
                        break;
                    } else if (arr[j] >= insertVal && j != 0) {
//                        System.out.println(arr[j]+"大于待比较元素 "+insertVal+" 发生了后移");
                        arr[j + 1] = arr[j];
                    } else if (arr[j] >= insertVal && j == 0) {
                        arr[j + 1] = arr[j];
                        arr[j] = insertVal;
                    }
                }

            }
        }
    }

 上面的两种代码实现都是从后面开始比的,如果我们冲前面开始比较,找到合适的位置之后再对需要移位的元素进行一个移位呢?实现代码如下:

    //通过for循环的形式实现,元素是从前面开始的
    public static void insertSortByFor(int[] arr){
        //这里实现的思路是从前往后比较,得到确定的位置之后再进行位移
        for (int i = 1; i < arr.length; i++) {
            int temp =0;
            for (int j = 0; j < i; j++) {
                //arr[i]这个数小于了arr[j]的这个数,arr[i]要放在arr[j]
                //先把arr[i]这个位置的数记录一下,随后把arr[j]以及之后的一段数据后移一位,腾出arr[j]的位置
                if (arr[i] j ;k--){
                        arr[k] = arr[k-1];
                    }
                    arr[j] = temp;
                }
            }

        }

    }

 

 

你可能感兴趣的:(Java算法与数据结构)