了解来自c K& R Book的ShellSort代码,第62页

时间:2016-12-24 17:51:12

标签: c shellsort

我试图在第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的原因。我无法找到原因。所以我认为有人可以解决这个问题吗?

1 个答案:

答案 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 = 2i = 4,该计划会比较51并进行互换;然后比较31并交换它们以确保这三个元素(135)处于正确的相对顺序。如果没有内部循环,则不会进行第二次交换。有可能在gap = 1的迭代中修复此问题,但1只与一个元素(3)交换,但不与2交换。

或者,对于更短但更模糊的答案:Shell排序为各种&#34;间隙大小执行循环&#34;在插入排序的变体。如果你知道插入排序,你知道它包含两个嵌套循环。如果删除最里面的循环,则会破坏内部插入排序。

最后,在您刚刚工作的示例中,您只是运气不好:如果输入(大部分)是排序的,即使是破坏的排序算法也可能起作用。这些东西很难测试。