整体:完成整个数组的排序(多次预排序直到最后插入排序gap=1)(n个值)gap=n(gap=gap/2或者gap=gap/3+1) gap
gap的值越大,大的值更快的调到后面,小的值可以更快的调到前面,越不接近有序。
gap的值越小,大的值更慢的调到后面,小的值可以慢的调到前面,越接近有序。
gap>1时时预排序,目的是让整体数值更加接近有序
gap == 1的时候就是直接插入排序,目的是让整体值有序。
无论gap是多少,它gap=gap/2后一定会等于1。
无论gap是多少,它gap=gap/3+1后一定会等于1。(预排次数少一点)
gap的值不是固定的,gap的值是随着整体n的大小变化而变化的。
一定要保证最后一次是1。这样才能让最后一次循环是直接插入排序,从而达到希尔排序的效果,使整体有序。
代码实现
【预排序】
单组
cpp复制代码
for (int i = 0; i < n - gap; i+=gap)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
如果是👇,会有什么错误?
for (int i = 0; i < n; i+=gap)
会出现越界,因为当i加到一组中的最后一个的时候,此时end=i,就没有end+gap了。
多组
如果想要实现多趟,就再套一个循环即可。
已知gap是指间隔,也就是说一共会有gap组,所以我们可以实现
方法一:三层循环(一组一组排)
cpp复制代码
//多趟
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 (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
方法二:多组并排
也就是让end在几组之间反复跳跃,第一组->第二组->第三组->第一组->第二组...
我们只需要把i的值改一下就可以了,改为i++,每次+1。这样就可以实现依次在每一个组里反复横跳了。
cpp复制代码
//多组并排
void ShellSort(int* a, int n)
{
//多组
int gap = 3;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
//一趟
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
void ShellSort(int* a, int n)
{
//整体
int gap = n;
while (gap > 1)
{
//每组
//gap = gap / 2;
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] > tmp)
{
a[end + gap] = a[end];
end -= gap;
}
else//<=
{
break;
}
}
a[end + gap] = tmp;
}
}
}