排序——希尔(Shell)排序及其与直接插入排序的对比

简介:

希尔(Shell)排序法是D.L.Shell在1959年发明的一种排序法,是第⼀个突破O(n2)的排序算法,是简单插⼊排序的改进版,其排序算法类似于简单插入排序,但它可以减少数据搬移的次数。希尔排序⼜叫缩⼩增量排序

排序原则:

将数据区分成特定间隔的几个小分块,以插入排序法排完区块内的数据后再逐渐减少间隔的距离。

排序方法:

希尔排序与直接插入排序非常相似,区别就在于直接插入排序是按照元素位置顺序进行依次判断,希尔排序是将间隔的元素进行插入,用一个实例来看:
例:

		原数组元素:6	9	2	3	4	7	5	1	
  1. 组中有8个元素,所以先设n=8,将其分为n/2=4个小区块,但是这几个小区块的元素并不是相连的,而是有间隔的,第一次分隔的四个小区块分别为(6, 4),
    (9, 7),(2, 5),(3, 1)

  2. 将每个区块中的两个元素进行直接插入排序,得到结果的四个新的区块为:
    (4, 6),(7 ,9),(2, 5),(1, 3)
    第一次分块并插入排序后的数组元素为:4 7 2 1 6 9 5 3

  3. 再次缩小区块为(n/2)/2=2块,第二次分隔后的两个小区块为:(4, 2, 6, 5)
    (7, 1, 9, 3)

  4. 将每个区块中的四个元素进行直接插入排序,得到结果的两个新的区块为:(2,4,5,6),(1, 3, 7, 9)
    第二次分块并插入排序后的数组元素为:2 1 4 3 5 7 6 7

  5. 再次缩小区块为((n/2)/2)/2=1块,第三次分隔后的仅剩一个区块,为:
    (2, 1, 4, 3, 5, 7, 6 ,9 )

  6. 将这个这个区块中的元素进行直接插入排序,得到的结果为:(1, 2, 3, 4, 5, 6, 7, 9)
    第三次分块并插入排序后的数组元素为:1 2 3 4 5 6 7 9

可以看出,随着每次对各分块进行排序后数组越来越趋近于有序,根据直接插入排序越有序越快的特点,希尔排序相对直接插入排序较快。

代码:

第一种写法:
import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {5,2,-6,8,-3,9,7,4,1,0,-5,3,6};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        ShellSort(arr);
        System.out.println("ShellSort-排序后:");
        System.out.println(Arrays.toString(arr));
    }

    public static void ShellSort(int[] arr){
        //设置分组,第一次为n/2组
        int gap = arr.length/2;
        while(gap>=1){
            for(int i = gap;i=0;j-=gap){
                    //若已排序区间元素大于tmp,进行交换
                    if(arr[j]>tmp){
                        arr[j+gap] = arr[j];
                    }else{
                        break;
                    }
                }
                arr[j+gap] = tmp;
            }
            gap = gap/2;
        }
    }
}

第二种写法:
   public static void ShellSort(int[] arr){
       //设置分组,第一次为n/2组
       int gap = arr.length/2;
       while(gap>=1){
           for(int i = gap;i=0 && arr[j]>tmp){
                   arr[j+gap] = arr[j];
                   j=j-gap;
               }
               arr[j+gap] = tmp;
           }
           gap = gap/2;
       }
   }

结果展示:

排序——希尔(Shell)排序及其与直接插入排序的对比_第1张图片

与直接插入排序进行对比:

关于直接插入排序,我前面的一篇文章有专门总结和实例展示,用的数据和本文相同点击查看:排序——直接插入排序
可以把链接中的代码拿过来与本文的代码进行对比,可以发现很多相似之处:

直接插入排序:
    public static void MyInsertSort(int[] arr){
        for (int i = 1; i < arr.length; i++) {
            int tmp = arr[i];
            int j = i-1;
            for (; j >=0; j--) {
                if(tmp 
希尔排序与之不同之处:
 public static void ShellSort(int[] arr){
        int gap = arr.length/2;			//@1:设置分组,第一次为n/2组
        while(gap>=1){
            for(int i = gap;i=0;j-=gap){		//@3:直接插入排序中为:for(;j>=0;j--){}

                    if(arr[j]>tmp){
                        arr[j+gap] = arr[j];		//@4:直接插入排序中为:arr[j+1] = arr[j];
                    }else{
                        break;
                    }
                }
                arr[j+gap] = tmp;			//@5:直接插入排序中为:arr[j+1] = tmp;
            }
            gap = gap/2;		//@6:直接插入中与分组无关
        }
    }
可以看出:

希尔排序与直接插入排序相比,仅仅是多了一个给原数组大小每次除2分组方式和用
while(gap>=1)来进行是否继续分组的判断,其余地方就是把直接插入排序中的+1,-1都改成+gap,-gap即可,因为直接插入排序是按照元素在数组中的顺序(即间隔为1)进行对比插入,希尔排序是以分组数(即间隔为gap)为间隔进行对比插入,仅此而已。理解了直接插入排序,那么希尔排序就很简单了。

你可能感兴趣的:(数据结构,排序)