希尔排序又称缩小增量法,是对直接插入排序的优化。
思路
思想:先去一合适任意值gap(至少大于1小于数组大小),先取下标为0的数,然后跳过gap个数,取其位置的数,再跳过gap个数...直到gap跳出整个数组后,这几个数为一组,之后取下标为1的数,跳过gap个数,取其位置的数...直到首取为止的下标为gap止,分为多个组合,对这几个 组合分为进行插入排序,这个过程称为预排序,达到接近有序的顺序,之后缩减gap数值重复操作,直到gap==1时,完成排序。
第一次排完后:
之后缩减gap的值再次分组(gap=2)
第二次排完后:
第三次gap=1,最后一次排序,整个数组为一组
排完后为
简单来说:1、取gap分组
2、分组
3、分别对每个组中的数进行排序
4、缩小gap的值重新分组排序直到gap==1
代码
首先写出两个“相邻”数的比较以及插入
//和直接插入法类似
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end]; //分组后每组相邻的数在整个数组下标差为gap
end -= gap;
}
else
break;
}
a[end + gap] = tmp;
之后在外围添加循环来实现每一gap组中所有数的比较插入
for (int i = j; i < n - gap; i += gap) //每组的排序
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end]; //分组后每组相邻的数在整个数组下标差为gap
end -= gap;
}
else
break;
}
a[end + gap] = tmp;
}
实现每组插入后,再通过循序实现所有组合的插入排序
for (int j = 0; j < gap; j++) //有gap组
{
for (int i = j; i < n - gap; i += gap) //每组的排序
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end]; //分组后每组相邻的数在整个数组下标差为gap
end -= gap;
}
else
break;
}
a[end + gap] = tmp;
}
}
实现了一次gap的组合,最后再通过循环实现所有gap缩小的排序
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{ //缩小gap重新分组排序直到gap==1
gap = gap / 3 + 1;
for (int j = 0; j < gap; j++) //有gap组
{
for (int i = j; i < n - gap; i += gap) //每组的排序
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end]; //分组后每组相邻的数在整个数组下标差为gap
end -= gap;
}
else
break;
}
a[end + gap] = tmp;
}
}
}
}
时间复杂度:O(nlogn)~O(N^2)
空间复杂度:O(1)
稳定性:不稳定