七-1, Java实现希尔排序的两种方法(交换法和位移法), 看了还不会代码写来打我!

查看以前文章: 希尔排序的基础定义和排序过程

1.希尔排序的基本思想

希尔排序是把记录按照下标的增量进行分组对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。blah blah blah…

2. 交换法实现希尔排序(效率不高)

  • 看上面这些被说烂了的定义还不如一步步具体的来看一个希尔排序是如何被实现出来的. 那么我们开始吧.
  1. 首先,我们都知道希尔排序是插入排序的改进,那么具体是如何实现这种改进的呢? 靠的是增量,实现跳跃式分组排序.

具体来说就是:
简单插入排序很循规蹈矩,不管数组分布是怎么样的,依然一步一步的对元素进行比较,移动,插入,比如[5,4,3,2,1,0]这种倒序序列,数组末端的0要回到首位置很是费劲,比较和移动元素均需n-1次。而希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1。希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后. 然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。

  1. 首先我们先来看一下直接插入排序的代码,因为这种排序相当于希尔排序的最后一趟,所以我们可以把直接插入排序看作是gap=1的希尔排序:
public class BasicSelectSort{
    public static void main(String[] args){
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        int temp;//临时变量

        //外层循环的作用: 遍历每个组, 
        //外层循环i=1代表的是增量gap为1,同时也说明待排队列被分为1个组(arr数组的这10个数就是一个组里的噢)
        //(gap=1代表相邻的每两个数进行比较, 如gap=2,代表的是每两个数隔了1个数进行比较)
        for(int i=1; i < arr.length; i++){
            //内层循环控制每个组中的数进行比较,(这里的j-=1的作用就是找到组里相邻的两个数)
            for(int j=i-1; j>=0; j-=1){
                //靠前的组员较大的话要跟后面的组员较小的进行交换
                if(arr[j] > arr[j+1]){
                    temp = num[j+1];
                    num[j+1] = num[j];
                    num[j] = temp;
                }
            }
        }
        //循环做完之后就是排序的最终结果了;
         System.out.println(Arrays.toString(arr));
    }
}

  1. 看完2之后,我们再把希尔排序的每一趟拆开来看,我们就可以很清楚的看到,希尔排序就是分了组的直接插入排序;

public class ShellSort{
    public static void main(String[] args){
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        int temp;//临时变量

        //希尔排序推荐的增量设置为 gap=lenth/2/2/2,每一次除以2,就是一趟排序,直到gap=1时排序结束
        
        //已知上面给定的待排序列长度lenth为10,所以第一趟排序我们的步长gap=10/2=5;
        //第一趟排序(gap = length/2=5)
        //外层循环i=5代表的是增量gap为5,同时也说明待排队列被分为了5个组
        //外层循环的作用: 遍历每个组,从i=5往后遍历了5个组, 此时的分组情况如上图所示: 
        //(gap=1代表相邻的每两个数进行比较, 如gap=5的话,代表的是每两个数之间隔了4个数进行比较)
        for(int i=5; i<arr.length; i++){
            //内层循环控制每个组中的数进行比较, 比如第一个组是 arr[5]=8和arr[0]=3相互比较
            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;
                }
            }
        }

        //第二趟希尔排序 10/2=5/2=2组 , 步长=2, 分了2个组
        for(int i=2; i<arr.length; i++){
            //控制每组中的数,两两比较,大的要交换到后面去
            for(int j=i-2; j>=0; j-=2){
                if(arr[j] > arr[j+2]){
                    temp = arr[j+2];
                    arr[j+2] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println("第二趟希尔排序的结果为: "+ Arrays.toString(arr));

        //第三趟希尔排序, 10/2=5/2=2/2=1组
        //i=1=gap
        for(int i=1; i<arr.length; i++){
            //控制每组中的数,两两比较,大的要交换到后面去
            for(int j=i-1; j>=0; j--){
                if(arr[j] > arr[j+1]){
                    temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println("第三趟希尔排序的结果为: "+ Arrays.toString(arr));
    }
  1. 我们把前面的整合起来, 就是一个完整的希尔排序了
public class ShellSort{
    public static void main(String[] args){
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        int temp;//临时变量
        int count = 0;

        //几个gap就是几趟排序
        for(int gap = arr.length/2; gap>0; gap/=2){
            
            for(int i=gap; i<arr.length; i++){
                //遍历各个组中的所有元素(共gap组,步长为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("希尔排序第"+(++count)+"轮="+Arrays.toString(arr));
        }
    }
}

3. 位移法实现希尔排序(效率较高)

跟前面直接插入排序的写法是大同小异的,都是通过移动数组,找到合适的插入位置之后再插入, 效率提升非常大;

直接上源码:

package DataStrcture.SortAlgorithmsDemo;

import java.util.Arrays;

public class UpdateShellSort {
    public static void main(String[] args) {
        int temp;
        int count=0;
       int[] arr = {8,9,1,7,2,3,5,4,6,0};
//        int arr[] = new int[80000];

//        //创建随机数的数组:
//        for (int i=0; i<arr.length; i++){
//            arr[i] = (int)(Math.random()*80000);
//        }
        long startTime = System.currentTimeMillis();

        //移位法
        //一个gap就是一趟排序噢
        for(int gap=arr.length/2; gap>=1; gap/=2){
            //这个for循环主要是负责遍历各个组的元素的末尾(gap, gap+1, gap+2,...)
            //注意是每个组的哦
            for(int i=gap; i<arr.length; i++){
                // 下面的做法主要就是倒序遍历每个组内的数据
                //通过比较并移动数组中的数, 待找到合适位置后直接放入即可;
                int j=i;
                temp = arr[j];

                while(j-gap >=0 && temp < arr[j-gap]){
                    arr[j] = arr[j-gap];
                    j -= gap;
                }
                arr[j] = temp;
            }
         System.out.println("希尔排序在第"+(++count)+"趟的排序结果为: "+ Arrays.toString(arr));
        }

    }
}

你学废了吗? 😂

posted @ 2022-05-26 20:31  青松城  阅读(50)  评论(0编辑  收藏  举报