希尔排序作为很有效率的排序之一,值得我们如了解他的原理和形式,所以今天我们浅谈的是希尔排序。
希尔排序的原理
希尔排序指的是:一组数按gap进行分组,每个间隔为gap的数为一组,这样形式的分组可以有gap组。
如图,如果我按gap=3来分组的话,一共可以分成三组,每组中的每个组间隔都为gap。
那么我们要是希尔排序的特性 :
1.希尔排序是对直接插入排序的优化;
2.当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,相当于直接插入排序。
所以从特性上来说希尔排序的内核还是和直接插入排序有一定的关系。让我们看看它的原理图:
因为我们分好的组,所以当我们按一组一组的排序,最后就会达到相对有序的情况,例如绿色组:
//部分代码展示:只排列绿色组
int end=0;
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;
会发现和我们预先的思路图的位置一样。那么如果我一组一组的排列且我要排列gap=3组时,的代码为:
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)
{
//为什么是i < n - gap,如果是n的话,当end+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;
}
}
}
那么如果我多组混合排序呢?**是不是相当于排完绿色组,i++后排红色组,然后i++排蓝色组,然后又到绿色…直到不满足限定条件为止。**如图:
void ShellSort(int* a, int n)
{
int gap = 3;
for(int j=0;j<gap;j++)
{
for (int i = 0; i < n - gap; i++)
{
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;
}
}
}
希尔排序的优化
上述我们确实可以对数组进行快速排序,但是如果我的数组很大很大那么gap=3他还合理吗?如果我的数组很小,那么gap=3合理吗?所以我们需要对希尔排序进行gap的优化。根据希尔排序的特性,当gap==1时,相当于直接插入排序,也就是将无序变为有序的最终步骤,那么我们让gap最终等于1即可,当gap>1时,都是预排序。
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
//这里gap只要保证等于1就可以,应为当gap==1的时候,相当于直接插入排序
//将前面的预排序最后整理。
for (int i = 0; i < n - gap; i++)
{
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;
}
}
}