import cn.idestiny.util.GeneratedArray;
/**
* @Auther: FAN
* @Date: 2018/8/25 22:25
* @Description:希尔排序
*
* 重点:设置增量
* 举例来说,含有1000个数据项的数组可能先以364为增量,然后以121为增量,以40为增量,
* 以13为增量,以4为增量,最后以 1为增量进行希尔排序。用来形成间隔的数列被称为间隔序列。
* 这里所表示的间隔序列由Knuth提出,此序列是很常用的。
* 数列以逆向形式从1开始,通过递归表达式 h=3*b+1 来产生,初始值为1。
*
* 当增量为arr.length/2的时候
* 1) 8,5,7,1,3,6,9.4 [8,3],[5,6] [7,9],[1,4]
* 2) 3,5,7,1,8,6,9,4 [3,7,8,9] [5,1,6,4]
* 3) 3,1,7,4,8,5,9,6 [3,1,7,4,8,5,9,6]
* 4) 1,3,4,5,6,7,8,9
**/
public class ShellSort {
public static void main(String[] args) {
int[] arr = GeneratedArray.randomGeneratedArray(10, 50, 100000);
long start = System.currentTimeMillis();
shellSort(arr);
GeneratedArray.isSorted(arr);
System.out.println(System.currentTimeMillis()-start);
}
public static void shellSort(int[] arr) {
//数组长度
int size = arr.length;
//设置间隔序列 详细请看文档注释
int h = 1;
while(h<size/3){
h = 3*h +1;
}
//根据增量分组,增量为1时,只需要插入排序算法微调即可
while(h>=1){
//对每个分组执行插入排序算法
for(int i = h;i<size;i++){
//记录插入值
int key = arr[i];
//插入值前一个元素的位置
int j = i-h;
//如果插入之比前一个值大,则插入之只需向后排列即可,不用在和前面的元素比较。
while(j>=0&&arr[j]>key){
//如果插入值比它前面的值小,则大值(插入值前面的值)向后移动一位,
arr[j+h] = arr[j];
//插入值之前的角标
j -= h;
}
//插入值最终应该放置的位置
arr[j+h] = key;
}
//缩小增量
h /= 3;
}
}
}