本质上也是插入排序:也称缩小量排序,针对arr={2,3,4,5,6,1}这种需要插入的数是较小数时,后移的次数明显增多,效率低。
基本思想:把元素按下标的一定增量分组,对每组数据直接使用插入排序算法排序,随着增量的逐渐减小,每组包含的元素的个数越来越多,当增量为1时,终止算法。
原始数组:8,9,1,7,2,3,5,4,6,0
初始增量:gap = length/2 = 5;
分组为:[8,3],[9,5],[1,4],[7,6],[2,0],但是原始的数据位置不变,组内数据位置变化为[3,8],[5,9],[1,4],[6,7],[0,2]。
第一次希尔排序为:3,5,1,6,0,8,9,4,7,2
第一次缩小增量:gap = length/2/2 = 2(向下取整);
分组为:[3,1,0,9,7]和[5,6,8,4,2],组内数据变化为[0,1,3,7,9]和[2,4,5,6,8]。
第二次希尔排序为:0,2,1,4,3,5,7,6,9,8
第二次缩小增量:gap = length/2/2/2 = 1
排序后得:0,1,2,3,4,5,6,7,8,9
希尔排序中,对有序序列在插入时采用交换法和移动法。
交换法:
public static void shellSort(int[] arr)
{
int temp = 0;
for (int gap = arr.length/2; gap > 0; gap/=2)
{
for (int i = gap; i < arr.length; i++)
{
//遍历各组中的所有元素,共gap组,步长为gap,每组有arr.length/gap个元素
for (int j = i - gap; j >= 0; j-=gap)
{
//若当前元素大于加上步长后的元素,则交换
if (arr[j] > arr[j+gap])
{
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
}
}
//移位法
public static void shellSort2(int[] arr)
{
//增量gap,并逐渐缩小增量
for (int gap = arr.length/2; gap > 0; gap/=2)
{
//从第gap个元素开始,逐个对其所在的组进行插入排序
for (int i = gap; i < arr.length; i++)
{
int j = i;
int temp = arr[j];
if (arr[j] < arr[j-gap])
{
while(j-gap >= 0 && temp < arr[j-gap])
{
//移动
arr[j] = arr[j-gap];
j -= gap;
}
//退出while时表明已经给temp找到了插入位置
arr[j] = temp;
}
}
}
}