在前面文章中介绍的直接插入排序,它对于已经基本有序的数据进行排序,效率会很高,而如果对于最初的数据是倒序排列的,则每次比较都需要移动数据,导致算法效率降低。

      希尔排序的基本思想就是:将需要排序的序列划分为若干个较小的序列,对这些序列进行直接插入排序,通过这样的操作可使需要排序的数列基本有序,最后再使用一次直接插入排序。

      在希尔排序中首先要解决的是怎样划分序列,对于子序列的构成不是简单地分段,而是采取将相隔某个增量的数据组成一个序列。一般选择增量的规则是:取上一个增量的一半作为此次子序列划分的增量,一般初始值元素的总数量。

  • 算法步骤:

初始化数组:

无标题.png

(1)使用元素总数量的一半(8)作为增量,将数屈打成招划分为8个序列,对这8个序列分别进行排序

无标题.png

(2)将增量缩小一半(值为4),重新划分子序列,得到4个子序列,对这4个子序分别进行排序,得到第2遍排序后的结果。

image.png

(3)缩小增量为2,得到如下结果:

无标题.png

(4)第4遍增量为1,得到最终的排序结果:

无标题.png

  • 代码实现:

public class ShellSort {

  

   public static void main(String[] args) {

      int arr[]={32,24,95,45,75,22,95,49,3,76,56,11,37,58,44,19,81};

      System.out.println("排序前:"+Arrays.toString(arr));

      sort(arr);

      System.out.println("排序后:"+Arrays.toString(arr));

   }

   public static void sort(int arr[]) {

      int d=arr.length/2;

      int x,j,k=1;

      while(d>=1) {

         for(int i=d;i<arr.length;i++) {

            x=arr[i];

            j=i-d;

            //直接插入排序,会向前找所适合的位置

            while(j>=0 && arr[j]>x) {

                //交换位置

                arr[j+d]=arr[j];

                j=j-d;

            }

            arr[j+d]=x;

         }

         d=d/2;

         System.out.println(""+ k++ +"趟:"+Arrays.toString(arr));

      }

   }

}

排序前:[32, 24, 95, 45, 75, 22, 95, 49, 3, 76, 56, 11, 37, 58, 44, 19, 81]

1趟:[3, 24, 56, 11, 37, 22, 44, 19, 32, 76, 95, 45, 75, 58,   95, 49, 81]

2趟:[3, 22, 44, 11, 32, 24, 56, 19, 37, 58, 95, 45, 75, 76,   95, 49, 81]

3趟:[3, 11, 32, 19, 37, 22, 44, 24, 56, 45, 75, 49, 81, 58,   95, 76, 95]

4趟:[3, 11, 19, 22, 24, 32, 37, 44, 45, 49, 56, 58, 75, 76,   81, 95, 95]

排序后:[3, 11, 19, 22, 24, 32, 37, 44, 45, 49, 56, 58, 75, 76, 81, 95, 95]