希尔排序是对直接插入排序的改良,也是冲破时间复杂度为O(n^2)的第一批算法之一
基本思想:将插入排序并不是一次性排完,而是分组进行插入排序。如一共有count个元素,设步长step1为count / 2, 即每走count / 2个元素分为一组,一共可以分为step1组,分别对每一组进行插入排序,得到新数组;此时缩短步长为step2=step1/2=count/2/2,每走step2个元素分为一组,一共可以分为step2个组,然后分别对每一组进行排序,得到新数组;此时缩短步长为step3 = step2 / 2 = count / 2 / 2 / 2......直至步长为1,在最后对所有元素进行插入排序进行微调,下面是带图详解
对于直接插入排序不懂可以看之前的博客https://blog.csdn.net/szy2333/article/details/83118677
一个数组,共有count个元素(如下图,图是偷的哈哈)
那么,初始步长为step = count / 2 = 5; 即步长为5,意思是每隔5步分为一组,一共有5组
分别对这五组元素进行排序,得到的结果为 3 5 1 6 0 8 9 4 7 2,并将步长缩短为step = step / 2 = 2;
此时步长为2,即每走两步得到的元素为一组,共分为2组
对这2组的元素分别进行插入排序,得到结果为 0 2 1 4 3 5 7 6 9 8,并将步长缩短为step = step / 2 = 1;此时步长为1,即所有元素为一个组
再对这些元素进行插入排序,得到最后的结果~
代码实现:
package BetterSort;
import java.util.Scanner;
public class ShellSort { //是改良的直接插入排序
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int array[] = new int[10]; //定义一个数组
System.out.println("请输入要排序的数:");
for(int index = 0; index < 10; index++) { //用一个循环控制数组的元素输入
int i = sc.nextInt();
array[index] = i;
}
shellSort(array);
printArray(array);
}
public static void shellSort(int[] array) {
//设定初始步长,且当步长大于零时,每次循环将步长缩减为step/2
for(int step = array.length / 2; step > 0; step /= 2) {
//设定数组的初始下标为0,且每走step步得到的元素分为一组,并对这组数进行插入排序
//startIndex++是初始下标为1,然后继续每走step步得到的元素分为一组,并对这组数进行插入排序
//直至下标为step-1时,遍历完本次所有组的元素,并返回上层循环,改变步长
for(int startIndex = 0; startIndex < step; startIndex++) {
insertSort(startIndex, array, step);
}
}
}
//插入排序
public static void insertSort(int startIndex, int[] array, int step) {
int i = 0;
int j = 0;
int t = 0;
for(i = startIndex + step; i < array.length; i += step) { //从下标为startIndex + step的第二个元素开始遍历
int tmp = array[i]; //建立临时变量,存储需要插入的元素值
for(j = startIndex; j < i && tmp >= array[j]; j += step) { //找到应该插入的位置
}
for(t = i; t > j; t -= step) { //将插入位置后面的元素后移一位
array[t] = array[t - step];
}
array[j] = tmp; //将元素值插入最终位置
}
}
public static void printArray(int[] array) { //打印数组元素的方法
for(int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.print("\n");
}
}