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