我正在阅读Robert Sedwick的C ++ Algorithms中的shell排序。
这里改变增量的外部循环导致这种紧凑的shellort实现,它使用增量序列1 4 13 40 121 364 1093 3280 9841。 。 。
template <class Item>
void shellsort(Item a[], int l, int r)
{
int h;
for (h = 1; h <= (r - l) / 9; h = 3 * h + 1);
for (; h > 0; h = h / 3)
{
for (int i = l + h; i <= r; i++)
{
int j = i; Item v = a[i];
while (j >= l + h && v < a[j - h])
{
a[j] = a[j - h]; j -= h;
}
a[j] = v;
}
}
}
我的问题是作者在什么基础上检查条件h&lt; =(r-l)/ 9,以及为什么作者除以9。
答案 0 :(得分:1)
循环:
for (h = 1; h <= (r - l) / 9; h = 3 * h + 1);
计算h
的初始值。该值必须小于它将用于的范围:
h <= (r - l)
每次此条件通过时,h
都会更新为3 * h + 1
,这意味着即使h
小于(r-l)
,更新后的值也可能会更大。为了防止这种情况,我们可以检查h
的下一个值是否会超过最大的索引:
(h * 3) + 1 <= (r - l)
这将确保h
小于数组的范围。
例如:假设我们有一个大小为42的数组,这意味着索引从0到41。使用上述条件:
h = 1, is (3 * 1 + 1) <= (41 - 0) ? yes! -> update h to 4
h = 4, is (3 * 4 + 1) <= (41 - 0) ? yes! -> update h to 13
h = 13, is (3 * 13 + 1) <= (41 - 0) ? yes! -> update h to 40
h = 40, is (3 * 40 + 1) <= (41 - 0) ? no! => h will begin at 40
这意味着我们的初始h
为40,因为h
仅略小于数组的范围,所以工作量很少,算法只检查以下内容:
这有点无用,第一次迭代只执行两次检查。较小的初始值h
意味着在第一次迭代中将完成更多的工作。
使用:
h <= (r - l) / 9
确保h
的初始值足够小,以允许第一次迭代执行有用的工作。作为额外的优势,它看起来也比之前的情况更清晰。
你可以用任何大于3的值替换9为什么大于3?确保(h * 3) + 1 <= (r - l)
仍然是真的!
但请记住不要使初始h
太小:Shell Sort基于Insertion Sort,它只能在小型或接近排序的数组上运行良好。就个人而言,我不会超过h <= (r - l) / 15
。