希尔排序也叫作缩小增量排序。
希尔排序的思想就是将一个序列分为若干子序列,在子序列内部进行直接插入排序【间隔非1的】,大幅的向目标位置迈进,而不是一步一步移动,收窄增量,最终为1,最终为1 时,其实就是一次直接插入排序,不过因为序列基本有序,所以这次的直接插入排序是效率最高,整体效率就提升很多,所以说希尔排序是直接插入排序的加强版。
直接插入排序的两个可以改进的点,1、增量为1,每次移动元素步幅小。2、元素无序 的话,需要大量的后移操作。
直接插入在以下情况中效率高
1比较记录较少的时候。
2记录本身是基本有序的,只需要少量 的插入操作。
所谓基本有序就是让大部分比较大的数据在序列后面,大部分比较小的数据在序列前面。
package com.houjun.sort; /** * 希尔排序,直接插入的增强版,直接插入是增量为1的插入排序。希尔排序增量递减 */ import java.util.Arrays; public class ShellSort { public static void main(String[] args) { int[] arr = { 7, 8, 2, 4, 5, 9, 3, 1, 6 }; shellsort(arr); System.out.println(Arrays.toString(arr)); } private static void shellsort(int[] arr) { // 希尔排序选出增量 int dk = arr.length / 3 + 1; while (dk != 1) { shellInsertSort(arr, dk); dk = dk / 3 + 1; } shellInsertSort(arr, 1); } /** * 增量为dk 的直接插入排序 * * @param arr * @param dk */ private static void shellInsertSort(int[] arr, int dk) { for (int i = dk; i < arr.length; i++) {// 遍历每个子序列;dk是第一个子序列的开头,dk+1是第二个子序列的开头,dk+n是第n+1个序列的开头 if (arr[i] < arr[i - dk]) {// 以任意值为增量,则一定存在i-dk的值,我们要判断当前值和他前面 的值 int j; int x = arr[i];// 待插入元素x,arr[i]这个位置会空出来 arr[i] = arr[i - dk];// 后移arr[i-dk],因为他的值比arr[i]大 for (j = i - dk; j >= 0 && arr[j] > x; j = j - dk) {// j 必须大于等于0,因为索引j要到子序列的第一个元素 // 通过循环,逐次后移比x大的值 // arr[j] = arr[j-dk];//第一次进来,j 等于每个子序列的首位,减去增量必为负数,不可这么写 arr[j + dk] = arr[j];// 把前面的值后移【后移就是赋给后面的位置】 } arr[j + dk] = x;// 把x赋给待插入的位置 } } } }