import java.util.Arrays;
import org.junit.Test;
/**
* 希尔排序
* 插入排序的一种
*/
public class HeerSort {
//希尔排序,它包括了交换法和移动法两种方式
public int[] heerSort(int[] arrays){
if(null == arrays){
throw new NullPointerException("arrays is null");
}
if(!(arrays.length>0)){
return arrays;
}
int[] sortArrays = Arrays.copyOf(arrays, arrays.length);
// sort(sortArrays);
sortOpt(sortArrays);
return sortArrays;
}
//移动法
private int[] sort(int[] sortArrays){
int length = sortArrays.length;
// 先求出最大区间值
int rCtl = 1;
while(rCtl*2+2<length){
rCtl = rCtl*2+2;
}
// 循环---将区间值减半
while (rCtl>0){
// 从第rCtl位开始,按区间进行插入排序
for(int i = rCtl;i<rCtl*2;i++){
// [1,*,*,*,3,*,*,*,2,*,*,*,7,*,*,*,5,*,*,*]
for(int j = i;j<length;j+=rCtl){
// 找到插入的位置
int insertnum = j;
int temp = sortArrays[j];
for(int c = j-rCtl;c>=0;c-=rCtl){
// 将在j前面的值,如果大于j,就往后挪一位
if(sortArrays[c]>temp){
sortArrays[c+rCtl] = sortArrays[c];
insertnum = c;
}else{
break;
}
}
sortArrays[insertnum] = temp;
}
}
rCtl=rCtl/2;
}
return sortArrays;
}
//代码优化写法
// 最外部不需要跨区间去循环,将外部跨区间循环与区间内部循环合成一个循环
// 因为本质还是从 0+fctl的位置一直遍历到最后一个
private void sortOpt(int[] arrays){
int len = arrays.length;
//定义区间大小
int fctl = 1;
//计算出最大区间
while(2*fctl+2<len){
fctl = 2*fctl+2;
}
while(fctl>0){
for(int i = fctl;i<len;i++){
int sortValue = arrays[i];
int insertKey = i;
//找到待排序的值所在的分组中该插入的位置
while((insertKey-fctl)>=0&&sortValue<arrays[insertKey-fctl]){
arrays[insertKey] = arrays[insertKey-fctl];
insertKey-=fctl;
}
arrays[insertKey] = sortValue;
}
fctl = fctl/2;
}
}
@Test
public void test(){
int [] arr1 = new int[]{9,3,5,7,2,8,4,1,6,2};
System.out.println(Arrays.toString(heerSort(arr1)));
}
}