1、简单插入排序存在的问题
我们看简单的插入排序可能存在的问题.
数组 arr = {2,3,4,5,6,1} 这时需要插入的数 1(最小), 这样的过程是:
{2,3,4,5,6,6}
{2,3,4,5,5,6}
{2,3,4,4,5,6}
{2,3,3,4,5,6}
{2,2,3,4,5,6}
{1,2,3,4,5,6}
结论: 当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.
**
2、希尔排序法介绍
希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。
**
3、希尔排序法基本思想
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止
4、希尔排序法的示意图
5、希尔排序的两种方法
5.1、交换法
5.1.1、源码
package com.study.sort;import java.util.Arrays;import java.util.Random;public class ShellSort {public static void main(String[] args) {int[] arr ={8,9,1,7,2,3,5,4,6,0};shellSort(arr);}//希尔排序:交换法public static void shellSort(int[] arr){int count = 1;//计算排序次数int temp = 0;//定义临时变量for (int gorp = arr.length / 2; gorp > 0; gorp /= 2){//将数组不断分组(arr.length / 2)循环for (int i = gorp; i < arr.length; i++){for (int j = i-gorp; j >= 0; j -= gorp){//遍历当前分组,一共gorp个组,步长为gorp;//如果当前元素大于加上步长后的那个元素,则交换if (arr[j] > arr[j+gorp]){temp = arr[j];arr[j] = arr[j+gorp];arr[j+gorp] = temp;}else {break;}}}System.out.println("第"+(count++)+"轮排序:"+ Arrays.toString(arr));}}
5.1.2、运行结果
5.1.3、测试时间
package com.study.sort;import java.util.Arrays;import java.util.Random;public class ShellSort {public static void main(String[] args) {int[] arr = new int[8000000];Random random = new Random();for (int i = 0; i < 8000000; i++) {arr[i] = random.nextInt(800000000);}//交换法时间:long l1 = System.currentTimeMillis();shellSort(arr);long l2 = System.currentTimeMillis();System.out.println("希尔排序(交换法)对"+arr.length+"个数据排序所花费的时间为:"+(l2-l1)+"ms");}//希尔排序:交换法public static void shellSort(int[] arr){int count = 1;//计算排序次数int temp = 0;//定义临时变量for (int gorp = arr.length / 2; gorp > 0; gorp /= 2){//将数组不断分组(arr.length / 2)循环for (int i = gorp; i < arr.length; i++){for (int j = i-gorp; j >= 0; j -= gorp){//遍历当前分组,一共gorp个组,步长为gorp;//如果当前元素大于加上步长后的那个元素,则交换if (arr[j] > arr[j+gorp]){temp = arr[j];arr[j] = arr[j+gorp];arr[j+gorp] = temp;}else {break;}}}//System.out.println("第"+(count++)+"轮排序:"+ Arrays.toString(arr));}}
测试结果:
希尔排序(交换法)对80000个随机数进行排序,只用了20ms,比之前的插入排序快了很多,其实希尔排序(交换法)只是在冒泡排序的基础上进行不断地分组,我们之前测试冒泡排序所用的时间为11s。
如果我们以插入排序为基础,进行希尔排序,那么时间应该会更短?
5.2、移位法
5.2.1、源码
package com.study.sort;import java.util.Arrays;import java.util.Random;public class ShellSort {public static void main(String[] args) {int[] arr ={8,9,1,7,2,3,5,4,6,0};shellSort2(arr);}//希尔排序:移位法public static void shellSort2(int[] arr){int count = 1;//计算排序次数for (int gorp = arr.length / 2;gorp>0; gorp /= 2){for (int i = gorp;i < arr.length;i++){int j = i;int temp = arr[j];if (arr[j] < arr[j-gorp]){while (j-gorp >= 0 && temp < arr[j-gorp]){arr[j] = arr[j-gorp];j -= gorp;}arr[j] = temp;}}System.out.println("第"+(count++)+"轮排序:"+ Arrays.toString(arr));}}}
5.2.2、运行结果

5.2.3、测试时间
package com.study.sort;import java.util.Arrays;import java.util.Random;public class ShellSort {public static void main(String[] args) {/* int[] arr ={8,9,1,7,2,3,5,4,6,0};shellSort2(arr);*/int[] arr = new int[80000];Random random = new Random();for (int i = 0; i < 80000; i++) {arr[i] = random.nextInt(800000000);}//交换法时间:long l1 = System.currentTimeMillis();shellSort(arr);long l2 = System.currentTimeMillis();System.out.println("希尔排序(交换法)对"+arr.length+"个数据排序所花费的时间为:"+(l2-l1)+"ms");//移位法时间:long l11 = System.currentTimeMillis();shellSort2(arr);long l22 = System.currentTimeMillis();System.out.println("希尔排序(移位法)对"+arr.length+"个数据排序所花费的时间为:"+(l22-l11)+"ms");}//希尔排序:交换法public static void shellSort(int[] arr){int count = 1;//计算排序次数int temp = 0;//定义临时变量for (int gorp = arr.length / 2; gorp > 0; gorp /= 2){//将数组不断分组(arr.length / 2)循环for (int i = gorp; i < arr.length; i++){for (int j = i-gorp; j >= 0; j -= gorp){//遍历当前分组,一共gorp个组,步长为gorp;//如果当前元素大于加上步长后的那个元素,则交换if (arr[j] > arr[j+gorp]){temp = arr[j];arr[j] = arr[j+gorp];arr[j+gorp] = temp;}else {break;}}}//System.out.println("第"+(count++)+"轮排序:"+ Arrays.toString(arr));}}//希尔排序:移位法public static void shellSort2(int[] arr){int count = 1;//计算排序次数for (int gorp = arr.length / 2;gorp>0; gorp /= 2){for (int i = gorp;i < arr.length;i++){int j = i;int temp = arr[j];if (arr[j] < arr[j-gorp]){while (j-gorp >= 0 && temp < arr[j-gorp]){arr[j] = arr[j-gorp];j -= gorp;}arr[j] = temp;}}//System.out.println("第"+(count++)+"轮排序:"+ Arrays.toString(arr));}}}

测试结果我们发现移位法比交换法还要快,80000个随机数只用短短的4ms就完成了排序,其实不难理解,之前测试的插入排序和冒泡排序所用时间为852ms和11s,很明显插入排序比冒泡排序快很多,所以在插入排序的基础上嵌套一层希尔排序后速度将起飞,嘿嘿。。
再看看800w个随机数所用的时间,如果理论上只要某算法的排序时间比插入排序还短,那么进行希尔排序后,时间可能还会更短
或**许这就是算法的魅力吧!
**

**
