1.希尔排序思路
希尔排序是一种基于插入排序的算法,通过将原始数据分成若干个子序列,然后对子序列进行插入排序,逐渐减小子序列的间隔,最后对整个序列进行一次插入排序。
1.分组直接插入排序,目标接近有序-----------gap>1
2.直接插入排序,目标有序-----------------------gap=1
2.分组排序思路分析
假设固定gap=3,那么以下数组可以分为三组
每一组都使用用直接插入排序,使数据有序
最后三组都排完后数组变成了:0,2,1,4,3,6,5,7,8,此时的结果接近有序
此时只需要再调用一次插入排序,即可让整个数组变得有序。
下面我们来实现一下这个
2.1思路代码
cpp
void ShellSort(int* a, int n)
{
int gap = 3;
for (int j = 0; j < gap; j++)
{
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];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
}
在每一组排序后都打印一下来观察
2.2结果显示
3.gap的设定
当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
当我们不再固定gap而是让他变化时,如下图gap=gap/2;
3.1动图演示
一般现在认为gap=gap/3+1较为合适,我们以此来实现一下代码
3.2最终代码实现
这里省去了一层for循环,把原本一组一组交换变为了组之间交替交换,时间复杂度没有改变。
cpp
//升序
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > a[end + gap])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
4.时间复杂度
记忆:O(N^1.3)
比O(N*logN)大,比O(N^2)小
希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定