递归方法的大O.

时间:2017-01-07 07:31:38

标签: recursion big-o

我很难确定简单递归方法的大O.如何计算这些方法的大O?

案例1)找到方法f的大O:

int f(int x){
    if(x<1) return 1;
    return f(x-1)+g(x);
}

int g(int x){
    if(x<2) return 1;
    return f(x-1)+g(x/2);
}

案例2)

int test(int n){
    if(x<=2) return 1;
    return test(n-2) * test(n-2);
}

案例3)

int T(int n){
    if(n<=1) return 1;
    return T(n/2)+T(n/2);
}

1 个答案:

答案 0 :(得分:2)

案例1

将基本案例放在一边(g(1) = g(0) = 1等),您可以用g重写f

f(n) = f(n-1) + g(n) <=> g(n) = f(n)-f(n-1)

我们知道g定义为:

g(n) = f(n-1) + g(n/2)

如果我们用上面重写的表单替换g(n/2),我们会得到:

g(n) = f(n-1) + f(n/2) + f(n/2-1)

这意味着我们可以在不f的任何引用的情况下重写g,将g(n)的原始定义中的f替换为上述公式:

f(n) = f(n-1) + f(n-1) + f(n/2) + f(n/2-1)

要仔细检查这是否等效,可以运行此程序,该程序接受整数n作为第一个参数,并打印原始f(n)的结果,后跟重写的{{ {1}}(在代码中称为f(n)):

f2

一些例子:

#include <stdio.h>

int g(int x);

int f(int x) {
    if (x < 1)
        return 1;
    return f(x-1)+g(x);
}

int g(int x) {
    if (x < 2)
        return 1;
    return f(x-1)+g(x/2);
}

int f2(int x) {
    if (x < 1)
        return 1;
    return f2(x-1)+f2(x-1)+f2(x/2)-f2(x/2-1);
}

int main(int argc, char *argv[]) {
    int n;
    sscanf(argv[1], "%d", &n);
    printf("%d\n", f(n));
    printf("%d\n", f2(n));
    return 0;
}

现在,如果你想象递归树,每个节点分支成4个子树($ ./a.out 10 1952 1952 $ ./a.out 11 3932 3932 $ ./a.out 12 7923 7923 $ ./a.out 13 15905 15905 $ ./a.out 14 31928 31928 $ ./a.out 15 63974 63974 f(n-1)f(n-1)f(n/2)各一个子树。 。每个子树的大小不相同,例如,如果我们下降到子树并且总是跟随最右边的2个分支中的任何一个,我们有一个深度为f(n/2-1)的二叉树。但是还有其他分支(如果我们始终遵循log(N)路径),其深度为f(n-1),并且分支为n两次。因此,我们可以说它绝对是指数级的。

获得确切的数字有点困难,但明显的上限是n-1 - 虽然这忽略了一些分支仅O(4^N)深的事实,所以实际上它&# 39;比log(N)好一点。

案例2

再次考虑递归树。在每个点,我们分支两次(O(4^N)test(n-2))。因为我们在每次调用时将test(n-2)减少2,所以树将n深,所以我们需要O(n/2)时间来遍历树 - 再次,指数增长。不是特别有趣。

(旁注:如果你在这里使用memoization,这将是线性的!)。

案例3

与案例2类似的逻辑,但这次树的深度为O(2^(n/2))(因为这需要将log(N)除以2的次数才能达到基本情况),所以我们得到N。所以它是线性的。