八大排序-希尔排序(四)
-
希尔排序:他是对插入排序的一个优化,核心的思想就是合理的选取增量,经过一轮排序后,就会让序列大致有序,然后再不断的缩小增量,进行插入排序,直到增量为 1,那整个排序结束。
-
原理图:
-
先来一个最基本的希尔排序
import java.util.Arrays; public class ArrayDemo4 { public static void main(String[] args) { //希尔排序:他是对插入排序的一个优化,核心的思想就是合理的选取增量,经过一轮排序后,就会让序列大致有序 //然后再不断的缩小增量,进行插入排序,直到增量为 1,那整个排序结束 //直接插入排序,,其实就是增量为1的希尔排序 int[] arr={46,55,13,42,17,94,5,70}; shellSort(arr); System.out.println(Arrays.toString(arr)); } private static void shellSort(int[] arr) { //这是直接插入排序,然后进行修改 //定义一个增量 int h=4; for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){//j=j-h 等于 j=j-4 是为了以4为增量进行交换 if (arr[j]<arr[j-h]){//j=j-h 等于 j=j-4 是为了以4为增量进行交换 swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } //第二轮 h=2; for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){ if (arr[j]<arr[j-h]){ swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } //第三轮 h=1; for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){ if (arr[j]<arr[j-h]){ swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } } //为了方便有重复代码,交换的位置用一个方法封装起来 public static void swapValue(int[] arr,int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }
-
再来个用for循环简单的优化
mport java.util.Arrays; public class ArrayDemo4 { public static void main(String[] args) { int[] arr={46,55,13,42,17,94,5,70}; shellSort(arr); System.out.println(Arrays.toString(arr)); } private static void shellSort(int[] arr) { //这是直接插入排序,然后进行修改 //定义一个增量 //这是用for循环来个简单的优化 for (int h=4;h>0;h/=2){ for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){ if (arr[j]<arr[j-h]){ swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } } } //为了方便有重复代码,交换的位置用一个方法封装起来 public static void swapValue(int[] arr,int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }
-
数组的元素过多,显然上次的优化已经不能用了(再优化),第一次这个增量选取数组长度的一半,然后不断的减半,希尔排序的思想,合理的选取这个增量。
import java.util.Arrays; public class ArrayDemo4 { public static void main(String[] args) { int[] arr={46,55,13,42,17,94,5,70}; shellSort(arr); System.out.println(Arrays.toString(arr)); } private static void shellSort(int[] arr) { //这是直接插入排序,然后进行修改 //希尔排序的思想,合理的选取这个增量(数组的元素过多,显然上次的优化已经不能用了) // 第一次这个增量选取数组长度的一半,然后不断的减半 for (int h=arr.length/2;h>0;h/=2){ for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){ if (arr[j]<arr[j-h]){ swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } } } //为了方便有重复代码,交换的位置用一个方法封装起来 public static void swapValue(int[] arr,int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }
-
还可以用克努特序列进行优化。
import java.util.Arrays; public class ArrayDemo4 { public static void main(String[] args) { int[] arr={46,55,13,42,17,94,5,70}; shellSort(arr); System.out.println(Arrays.toString(arr)); } private static void shellSort(int[] arr) { //这是直接插入排序,然后进行修改 //我们第一次的增量选择数组长度一样,还不是很好,我们可以使用一种序列叫做克努特序列 //int h=1; //h=h*3+1;//1,4,13,40,121,364 int jiange=1; while (jiange<=arr.length/3){ jiange=jiange*3+1; } //System.out.println(jiange); 判断现在数组适合什么间隔 for (int h=jiange;h>0;h=(h-1)/3){ //原本对应的原理是h=h*3+1,现在返回去就是h=(h-1)/3 for (int i = h; i < arr.length; i++) { for (int j =i;j>h-1;j-=h){ if (arr[j]<arr[j-h]){ swapValue(arr,j,j-h);//这是直接用封装的方法进行调用 } } } } } //为了方便有重复代码,交换的位置用一个方法封装起来 public static void swapValue(int[] arr,int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }