思路:
比如,我们有1000个数据项需要排序,利用h=3*h+1产生的间隔序列为:1,4,13,40,12,121,364,1093,3280…0000000000
364就是第一轮排序的步长,接下来依次是121,12…
1.确定第一次排序的步长h
2.排序
—while(结束条件步长为零)
--------for
---------------对从第一对到第h对拆分的数组排序
---------------------插入排序
--------计算下一轮的步长:(h-1)/3
代码
public void shellSort(int arr[]){
int length = arr.length,h=1;//h为步长
while(3*h+1<length){
h = 3*h+1;
}
int previous = 0,temp=0;
while(h>0){
for(int i=0;i<h;i++){
int targetIndex = i+h;
while(targetIndex<length){
temp = arr[targetIndex];
previous = targetIndex - h;//前一个数组下标
while(previous>=0&&arr[previous]>temp){
arr[previous+h] = arr[previous];//把大的数依次往后挪
previous = previous-h;//多减了一个h
}
arr[previous+h] = temp;
targetIndex = targetIndex + h;
}
}
h = (h-1)/3;//计算下一轮步长,当然这样写乘过来除过去,浪费了
}
}
优化版 (不是我的思路,书上的)
public void shellSort2(int arr[]){
int i,h,target,z,pre,increment[] = new int[20];
/*
* increment存储了步长数据
* i为步长的数组下标,即i也控制了排序几轮
* h为当前一轮排序的步长
* z为当前一轮排序的组数
* taget为插入排序待插入数据
* pre为这组数据前1~n的数组下标
* */
for(h = 1,i = 0;h < arr.length;i++){
increment[i] = h;
h = 3*h + 1;
}
for(i--;i >= 0;i--){//控制排多少轮
h = increment[i];
for(z = h;z < 2*h;z++){//排每轮的h个组数据
for(target = z;target < arr.length;){//排每一组数据(插入排序)
int temp = arr[target];
pre = target-h;
while(pre>=0&&arr[pre]>temp){
arr[pre+h] = arr[pre];
pre -= h;
}
arr[pre+h] = temp;
target += h;
}
}
}
}