我试图在第62页了解K& R书中的ShellSort代码。但是有一部分我不确定。
所以这是本书的原始代码:
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = gap; i < n; i++) {
for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
}
}
}
我试图理解为什么会有第三个循环。它可能只是不可能吗?
以下是代码的更改版本(我认为也可以使用的代码):
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = gap; i < n; i++) {
j = i - gap;
if (v[j] > v[j + gap]) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
}
}
}
当我运行代码时,它输出与第一个代码相同的东西:
输出:
12345679
但肯定有使用for
的原因。我无法找到原因。所以我认为有人可以解决这个问题吗?
答案 0 :(得分:2)
如果您追踪算法的作用,您可能会更好地了解正在发生的事情。这是一个程序版本,带有一些额外的打印语句:
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
printf("enter outer loop with gap = %d\n", gap);
for (i = gap; i < n; i++) {
printf("- enter second loop with i = %d\n", i);
for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
printf("- after innermost loop:");
print_array(v, n);
}
}
}
(我省略了print_array
的定义。)
作为评论者的建议,使用数组{ 5, 4, 3, 2, 1 }
调用此方法,可以输出:
5 4 3 2 1
enter outer loop with gap = 2
- enter second loop with i = 2
- after innermost loop: 3 4 5 2 1
- enter second loop with i = 3
- after innermost loop: 3 2 5 4 1
- enter second loop with i = 4
- after innermost loop: 1 2 3 4 5
enter outer loop with gap = 1
- enter second loop with i = 1
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 2
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 3
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 4
- after innermost loop: 1 2 3 4 5
1 2 3 4 5
但是,如果我使用您的代码,只使用if
代替最里面的for
循环,会发生以下情况:
5 4 3 2 1
enter outer loop with gap = 2
- enter second loop with i = 2
- after swap: 3 4 5 2 1
- enter second loop with i = 3
- after swap: 3 2 5 4 1
- enter second loop with i = 4
- after swap: 3 2 1 4 5
enter outer loop with gap = 1
- enter second loop with i = 1
- after swap: 2 3 1 4 5
- enter second loop with i = 2
- after swap: 2 1 3 4 5
- enter second loop with i = 3
- after swap: 2 1 3 4 5
- enter second loop with i = 4
- after swap: 2 1 3 4 5
2 1 3 4 5
结果不正确,因为1
未传播到数组的开头。这是由于缺少内循环。在原始版本的gap = 2
和i = 4
,该计划会比较5
和1
并进行互换;然后比较3
和1
并交换它们以确保这三个元素(1
,3
,5
)处于正确的相对顺序。如果没有内部循环,则不会进行第二次交换。有可能在gap = 1
的迭代中修复此问题,但1
只与一个元素(3
)交换,但不与2
交换。
或者,对于更短但更模糊的答案:Shell排序为各种&#34;间隙大小执行循环&#34;在插入排序的变体。如果你知道插入排序,你知道它包含两个嵌套循环。如果删除最里面的循环,则会破坏内部插入排序。
最后,在您刚刚工作的示例中,您只是运气不好:如果输入(大部分)是排序的,即使是破坏的排序算法也可能起作用。这些东西很难测试。