Live2D
Fork me on GitHub

17、排序算法-希尔排序

来源:https://www.bilibili.com/video/BV1B4411H76f?p=60

一、思路

希尔排序:本质还是一种插入排序,分组和之前的简单插入排序不一样,这里给出一个增量,按照这个增量进行分组,增量是逐渐减小的,减小为1时进行最后一次排序。所以希尔排序也可以叫缩小增量排序。

 

例:[8,9,1,7,2,3,5,4,6,0],从小到大排列

这里如果按照简单插入排序的话,0在一个很尴尬的位置,它需要跟所有数据进行比较,所有数据都需要后移。

如果按照希尔排序:

第一趟:给定一个增量gap=length/2。length是数组的长度10,所以这里的增量为5。从第一个数据开始,以增量作为步长进行分组和比较。下标0和下标5为一组进行比较,[8,3]需要交换位置;下标1和下标6为一组进行比较,[9,5]需要交换位置;下标2和下标7为一组进行比较,[1,4]不需要交换位置;下标3和下标8为一组进行比较,[7,6]需要交换位置;下标4和下标9为一组进行比较,[2,0]需要交换位置。本次比较完成后,数组变成了[3,5,1,6,0,8,9,4,7,2]。

第二趟:gap=gap/2。这里增量为2。从第一个数据开始,下标为0、2、4、6、8的数据进行比较,即[3,1,0,9,7]进行插入排序,完成后为[0,1,3,7,9],与原来的位置一一对应;同理[5,6,8,4,2]进行插入排序,完成后为[2,4,5,6,8],与原来的位置一一对应。本次比较完成后,数组变成了[0,2,1,4,3,5,7,6,9,8]。

第三趟:gap=gap/2。这里增量为1。从第一个数据开始,插入排序。本次比较完成后,数组变成了[0,1,2,3,4,5,6,7,8,9]。

gap=gap/2=0。完成排序。

二、实现

 1 //希尔排序
 2 public class ShellSort {
 3     public static void main(String[] args) {
 4         int[] arr = {8,9,1,7,2,3,5,4,6,0};
 5         System.out.println(Arrays.toString(arr));
 6 
 7         shellSort(arr);
 8         System.out.println(Arrays.toString(arr));
 9 
10     }
11 
12     public static void shellSort(int[] arr){
13         for (int gap = arr.length/2; gap > 0; gap/=2) {
14             //从gap位置开始,后面的要依次与前面的比较(包括gap位置的数据)
15             for (int i = gap; i < arr.length; i++) {
16                 //按照组进行比较,不合适就交换
17                 for (int j = i - gap; j >= 0; j-=gap) {
18                     if(arr[j] > arr[j + gap]){
19                         int temp = arr[j];
20                         arr[j] = arr[j + gap];
21                         arr[j + gap] = temp;
22                     }
23                 }
24             }
25         }
26     }
27 }

结果

[8, 9, 1, 7, 2, 3, 5, 4, 6, 0]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这里不太好的地方就是,没有用到之前简单插入排序的思路,这里用的是交换。我们把上面的方法也叫交换式希尔排序。下面对这个排序方法进行改进,加入插入排序的思路,这里也叫移位式希尔排序

 1     public static void shellSort2(int[] arr){
 2         for (int gap = arr.length/2; gap > 0; gap/=2) {
 3             //典型的插入排序,从gap位置开始,前面的属于有序,后面的要比较(包括gap位置的数据)
 4             for (int i = gap; i < arr.length; i++) {
 5                 int insertIndex = i - gap;
 6                 int insertVal = arr[i];
 7                 while (insertIndex >= 0 && insertVal < arr[insertIndex]){
 8                     arr[insertIndex + gap] = arr[insertIndex];
 9                     insertIndex -= gap;
10                 }
11                 if(arr[insertIndex + gap] != i){//发生过移位操作
12                     arr[insertIndex + gap] = insertVal;
13                 }
14             }
15         }
16     }

测试结果与上面的一样。需要注意,这里的移位式希尔排序是我自己根据简单插入式排序改的,跟视频中讲解的有一点点不同,思路是一样的,程序中的变量名是对照前面的简单插入排序来的,我感觉这样更好理解一点。

posted @ 2020-06-19 13:25  -小二黑-  阅读(172)  评论(0编辑  收藏  举报