基本思想
1.将整个待排序数组分为若干个子序列,相隔固定增量(步长)
2.将若干子序列分别进行插入排序,待若干子序列排序完后,缩小增量
3.重复步骤2
4.最后整体再进行一次插入排序(当步长=1时)
希尔排序代码
//a[]数组 k步长
public void shellSort(int a[]){
//先获取步长
int h=1;//步长初始化
while(h<(a.length)/2){//a.length=7 h<=3,分为三组{5,4},{9,6},{2,1}
h=h*2+1;//1*2+1=3
}
while(h>0) {
for (int i = h; i < a.length; i++) {//从索引为3开始遍历,比较时,-3即可
int temp = a[i];//记录右边的值
if (a[i] < a[i - h]) {//前面的值大于后面的值,交换
int j = i-h;//记录左边的索引
for (; j >=0&&a[j] - temp > 0 ; j-=h) {//a[j]
a[j+h] = a[j];
System.out.println("--------start---------"+temp);
System.out.println(Arrays.toString(a));
}
a[j+h] = temp;
System.out.println(Arrays.toString(a));
System.out.println("----------end--------");
}
System.out.println(Arrays.toString(a));
}
h=(h-1)/2;
}
System.out.println();
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
图解:
复杂度分析
空间复杂度:使用了一个temp临时存放数据的变量以及一个步长值变量
时间复杂度:时间复杂度上,虽然是三层循环,可能有人会直接判定该复杂度为O(n3),但是事实并非如此
1.首先,最外层循环次数为log2n
2.其次,第二层循环的循环次数为n
3.最后内循环的次数是远低于n数量级的,因为当分组多时,元素就少,循环次数也就少,当分组越来越多,元素也越来越多时,实际上元素已经接近于有序,所以我们几乎可以视为循环次数不增加,因此希尔排序的时间复杂度在O(n*log2n)和O(n2)之间,约为O(n1.3)