Java实现插入排序及其优化 Shell Sort

本文带来八大排序算法之希尔排序。

希尔排序可以认为是插入排序的一种优化算法。在上一篇插入排序的举例数组中,当第二轮排序过后,数组变为[34, 101, 119, 1],此时如果将最后一个元素放到最前,则要经历如下过程:

[34, 101, 119, 119]

[34, 101, 101, 119]

[34, 34, 101, 119]

[1, 34, 101, 119]

结论:当需要插入的数是较小的数时,数组前方的元素后移次数明显增多,对效率有影响。

希尔排序也是一种插入排序,它是简单插入排序经过改进后的一个更高效的版本,也称为缩小增量排序。希尔排序是把记录按下标的一定增量(gap)分组,对每组使用直接插入排序算法排序 ;随着增量的逐渐缩小,每组包含的元素越来越多,当增量缩减至1时,整个数组恰好被分成一组,算法结束。

最后一轮排序后结果如下: 

希尔排序有交换法和移位法两种方法,交换法效率较低,移位法效率较高。现在分别实现如下两种方法,并给出希尔排序的推导过程,数组以 {8,9,1,7,2,3,5,4,6,0}为例

推导过程如下:

数组长度为10,因此第一次gap = 10/2 = 5

        //推导过程
        int temp = 0;
        //第1轮排序,将10个数据分成5组
        for(int i=5; i<arr.length; i++){ //此循环只是为了将数组分为5组
            //遍历各组中的所有元素(共有5组,每组2个元素,步长5、(j = j-5,意味着从后往前数)
            for(int j=i-5; j>=0; j -= 5){
                //如果当前元素大于加上步长后的那个元素,说明则需要交换
                if(arr[j] > arr[j+5]){
                    temp = arr[j];
                    arr[j] = arr[j+5];
                    arr[j+5] = temp;

                }
            }

        }
        System.out.println("希尔排序第1轮= " + Arrays.toString(arr));

        //第2轮排序,将10个数据分成5/2 = 2组
        for(int i=2; i<arr.length; i++){ //此循环只是为了将数组分为2组
            //遍历各组中的所有元素(共有2组,每组5个元素,步长2
            for(int j=i-2; j>=0; j -= 2){
                //如果当前元素大于加上步长后的那个元素,说明则需要交换
                if(arr[j] > arr[j+2]){
                    temp = arr[j];
                    arr[j] = arr[j+2];
                    arr[j+2] = temp;

                }
            }
        }
        System.out.println("希尔排序第2轮= " + Arrays.toString(arr));

        //第3轮排序,将10个数据分成2/2 = 1组
        for(int i=1; i<arr.length; i++){ //此循环只是为了将数组分为1组
            //遍历各组中的所有元素
            for(int j=i-1; j>=0; j -= 1){
                //如果当前元素大于加上步长后的那个元素,说明则需要交换
                if(arr[j] > arr[j+1]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;

                }
            }
        }
        System.out.println("希尔排序第3轮= " + Arrays.toString(arr));

交换法代码实现:

    public static void shellSort(int[] arr){
        //希尔排序 第一轮排序
        int temp = 0;
        int cnt = 0;
        for(int gap = arr.length/2; gap > 0; gap /= 2){
            for(int i=gap; i<arr.length; i++){ 
                 //遍历各组中的所有元素(共有gap组,步长gap、(j = j-gap,意味着从后往前数))
                for(int j=i-gap; j>=0; j -= gap){
                    
                    if(arr[j] > arr[j+gap]){
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;

                    }
                }
            }
            System.out.println("希尔排序第" + (++cnt) + "轮:" + Arrays.toString(arr));
        }
    }

移位法代码实现(在交换时,采取只交换一次的方式):

    public static void shellSort2(int[] arr){
        int cnt = 0;
        //增量为gap, 并逐步缩小增量
        for(int gap = arr.length/2; gap > 0; gap /= 2){

            for(int i=gap; i<arr.length; i++){
                int insertIndex = i;
                int insertValue = arr[insertIndex];
                if(arr[insertIndex] < arr[insertIndex - gap]){
                    while(insertIndex - gap >=0 && insertValue < arr[insertIndex - gap]){
                        arr[insertIndex] = arr[insertIndex - gap];
                        insertIndex -= gap;
                    }
                    //当退出while后,就给insertValue找到了插入的位置
                    arr[insertIndex] = insertValue;
                } 

            }
            System.out.println("移位-希尔排序第" + (++cnt) + "轮:" + Arrays.toString(arr));
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值