【问题标题】:Complexity in a recursion algorithm递归算法的复杂性
【发布时间】:2015-11-05 13:43:46
【问题描述】:

我目前正在大学学习数据结构,偶然发现了一个关于递归复杂性的问题。

鉴于此代码:

Unsigned func (unsigned n)
{
 if (n ==0) return 1;
 if(n==1) return 2;

 \\do somthing(in O(1) )

 return func(n-1) + func(n-1);
} 

我知道代码的作用。我知道现在的形式,时间复杂度是O(2^n)。

然而,我的问题是:如果不是我将编写的代码的最后一个返回调用:return 2*func(n-1),时间复杂度会改变吗?

我知道,就内存复杂度而言,我们说的是递归占用空间的显着减少,但就时间复杂度而言,会有什么变化吗?

我使用递归函数进行了数学运算,并了解到时间复杂度不会发生变化,对吗?

【问题讨论】:

    标签: algorithm recursion big-o time-complexity complexity-theory


    【解决方案1】:

    这个方法只有O(n),因为如果你用 5 运行它,它会用 4 递归,然后用 3 等等。

    Unsigned func (unsigned n)
    {
     if (n ==0) return 1;
     if(n==1) return 2;
    
     \\do somthing(in O(1) )
    
     return 2*func(n-1);
    }
    

    但是这个呢:

    Unsigned func (unsigned n)
    {
     if (n ==0) return 1;
     if(n==1) return 2;
    
     \\do somthing(in O(1) )
    
     return func(n-1) + func(n-1);
    }
    

    例如 func(5) 它将首先执行如下

    5 -> 4 -> 3 -> 2 -> 1
    

    然后它返回到2,但在那里它会执行“第二”部分,所以整个过程看起来像

    5 -> 4 -> 3 -> 2-> 1; 2-> 1; 3->2->1; etc.
    

    因此,它确实将复杂性从 O(n) 大幅更改为 O(2^n)


    让我们试试这个代码的实际例子:

    public class Complexity {
        private static int counter;
        public static void main(String[] args) {
            for (int i = 0; i < 20; i++) {
                counter = 0;
                func(i);
                System.out.println("For n="+i+" of 2*func the number of cycles is " + counter);
                counter = 0;
                func2(i);
                System.out.println("For n="+i+" of func + func the number of cycles is " + counter);
            }
        }
    
        public static int func(int n) {
            counter++;
            if (n == 0) {
                return 1;
            }
            if (n == 1) {
                return 2;
            }
            return 2 * func(n - 1);
        }
    
        public static int func2(int n) {
            counter++;
            if (n == 0) {
                return 1;
            }
            if (n == 1) {
                return 2;
            }
            return func2(n - 1) + func2(n - 1);
        }    
    }
    

    有这个输出:

    For n=0 of 2*func the number of cycles is 1
    For n=0 of func + func the number of cycles is 1
    For n=1 of 2*func the number of cycles is 1
    For n=1 of func + func the number of cycles is 1
    For n=2 of 2*func the number of cycles is 2
    For n=2 of func + func the number of cycles is 3
    For n=3 of 2*func the number of cycles is 3
    For n=3 of func + func the number of cycles is 7
    For n=4 of 2*func the number of cycles is 4
    For n=4 of func + func the number of cycles is 15
    For n=5 of 2*func the number of cycles is 5
    For n=5 of func + func the number of cycles is 31
    For n=6 of 2*func the number of cycles is 6
    For n=6 of func + func the number of cycles is 63
    For n=7 of 2*func the number of cycles is 7
    For n=7 of func + func the number of cycles is 127
    For n=8 of 2*func the number of cycles is 8
    For n=8 of func + func the number of cycles is 255
    For n=9 of 2*func the number of cycles is 9
    For n=9 of func + func the number of cycles is 511
    For n=10 of 2*func the number of cycles is 10
    For n=10 of func + func the number of cycles is 1023
    For n=11 of 2*func the number of cycles is 11
    For n=11 of func + func the number of cycles is 2047
    For n=12 of 2*func the number of cycles is 12
    For n=12 of func + func the number of cycles is 4095
    For n=13 of 2*func the number of cycles is 13
    For n=13 of func + func the number of cycles is 8191
    For n=14 of 2*func the number of cycles is 14
    For n=14 of func + func the number of cycles is 16383
    For n=15 of 2*func the number of cycles is 15
    For n=15 of func + func the number of cycles is 32767
    For n=16 of 2*func the number of cycles is 16
    For n=16 of func + func the number of cycles is 65535
    For n=17 of 2*func the number of cycles is 17
    For n=17 of func + func the number of cycles is 131071
    For n=18 of 2*func the number of cycles is 18
    For n=18 of func + func the number of cycles is 262143
    For n=19 of 2*func the number of cycles is 19
    For n=19 of func + func the number of cycles is 524287
    

    但如果你记得已经计算过的结果,即使使用第二种方法,复杂度仍然是O(n):

    public class Complexity {
        private static int counter;
        private static int[] results;
    
        public static void main(String[] args) {
            for (int i = 0; i < 20; i++) {
                counter = 0;
                func(i);
                System.out.println("For n="+i+" of 2*func the number of cycles is " + counter);
                counter = 0;
                func2(i);
                System.out.println("For n="+i+" of func + func the number of cycles is " + counter);
                counter = 0;
                results = new int[i+1];
                func3(i);
                System.out.println("For n="+i+" of func + func with remembering the number of cycles is " + counter);
            }
        }
    
        public static int func(int n) {
            counter++;
            if (n == 0) {
                return 1;
            }
            if (n == 1) {
                return 2;
            }
            return 2 * func(n - 1);
        }
    
        public static int func2(int n) {
            counter++;
            if (n == 0) {
                return 1;
            }
            if (n == 1) {
                return 2;
            }        
            return func2(n - 1) + func2(n - 1);
        }
    
        public static int func3(int n) {
            counter++;
            if (n == 0) {
                return 1;
            }
            if (n == 1) {
                return 2;
            }
    
            if (results[n] == 0){
                results[n] = func3(n - 1) + func3(n - 1);
            }
    
            return results[n];
        }        
    }
    

    有这个输出:

    For n=0 of 2*func the number of cycles is 1
    For n=0 of func + func the number of cycles is 1
    For n=0 of func + func with remembering the number of cycles is 1
    For n=1 of 2*func the number of cycles is 1
    For n=1 of func + func the number of cycles is 1
    For n=1 of func + func with remembering the number of cycles is 1
    For n=2 of 2*func the number of cycles is 2
    For n=2 of func + func the number of cycles is 3
    For n=2 of func + func with remembering the number of cycles is 3
    For n=3 of 2*func the number of cycles is 3
    For n=3 of func + func the number of cycles is 7
    For n=3 of func + func with remembering the number of cycles is 5
    For n=4 of 2*func the number of cycles is 4
    For n=4 of func + func the number of cycles is 15
    For n=4 of func + func with remembering the number of cycles is 7
    For n=5 of 2*func the number of cycles is 5
    For n=5 of func + func the number of cycles is 31
    For n=5 of func + func with remembering the number of cycles is 9
    For n=6 of 2*func the number of cycles is 6
    For n=6 of func + func the number of cycles is 63
    For n=6 of func + func with remembering the number of cycles is 11
    For n=7 of 2*func the number of cycles is 7
    For n=7 of func + func the number of cycles is 127
    For n=7 of func + func with remembering the number of cycles is 13
    For n=8 of 2*func the number of cycles is 8
    For n=8 of func + func the number of cycles is 255
    For n=8 of func + func with remembering the number of cycles is 15
    For n=9 of 2*func the number of cycles is 9
    For n=9 of func + func the number of cycles is 511
    For n=9 of func + func with remembering the number of cycles is 17
    For n=10 of 2*func the number of cycles is 10
    For n=10 of func + func the number of cycles is 1023
    For n=10 of func + func with remembering the number of cycles is 19
    For n=11 of 2*func the number of cycles is 11
    For n=11 of func + func the number of cycles is 2047
    For n=11 of func + func with remembering the number of cycles is 21
    For n=12 of 2*func the number of cycles is 12
    For n=12 of func + func the number of cycles is 4095
    For n=12 of func + func with remembering the number of cycles is 23
    For n=13 of 2*func the number of cycles is 13
    For n=13 of func + func the number of cycles is 8191
    For n=13 of func + func with remembering the number of cycles is 25
    For n=14 of 2*func the number of cycles is 14
    For n=14 of func + func the number of cycles is 16383
    For n=14 of func + func with remembering the number of cycles is 27
    For n=15 of 2*func the number of cycles is 15
    For n=15 of func + func the number of cycles is 32767
    For n=15 of func + func with remembering the number of cycles is 29
    For n=16 of 2*func the number of cycles is 16
    For n=16 of func + func the number of cycles is 65535
    For n=16 of func + func with remembering the number of cycles is 31
    For n=17 of 2*func the number of cycles is 17
    For n=17 of func + func the number of cycles is 131071
    For n=17 of func + func with remembering the number of cycles is 33
    For n=18 of 2*func the number of cycles is 18
    For n=18 of func + func the number of cycles is 262143
    For n=18 of func + func with remembering the number of cycles is 35
    For n=19 of 2*func the number of cycles is 19
    For n=19 of func + func the number of cycles is 524287
    For n=19 of func + func with remembering the number of cycles is 37
    

    【讨论】:

    • 那么我对 func(n-1) + func(n-1) 的递归调用以 O(2^n) 的复杂度运行是否正确?另外,为什么我的递归公式,当我把它写在纸上并计算时,我发现它们都有相同的时间复杂度?
    • @Tom - 是的,它以 O(2^n) 的复杂度运行...关于您的公式 - 您使用错误或公式错误。将该公式发布到您的问题中,也许我们可以告诉您出了什么问题。
    • 我的公式是:T(n) = 2T(n-1) while T(0)=1,T(1)= 2。我使用了“发布方法”,得到了一般函数:T(n) = 2^i *T(n-i)。在定位我的停止条件(如 i = n-1 或 i = n-2)后,我达到了 T(n) = 2^(n-1) *T(1) = (2^n)/2 的复杂性 - ------> O(2^n)。其他停止条件的结果相同。我做错了什么,因为我为两种类型的代码得到了相同的公式。
    • T(n) = 2T(n-1) 在2*func(n-1) 中是不正确的,因为T(n) 不做T(n-1) 两次,它只做一次然后将结果乘以2,这是不同的事情。
    • 你能帮我写出适合 2*func(n-1) 场景的 T(n) 吗?我如何模拟它只调用一个然后将结果乘以 2 的事实?
    【解决方案2】:

    这取决于您的编程/算法语言的语义。

    如果f(n) 的意思是“无论之前是否使用相同的参数调用该函数”(大多数编程语言都是如此),那么您的更改会将复杂性显着降低到 O(n )。每减少一个参数,您就有一个 O(1) 函数调用。

    否则(如果您谈论的是纯函数并记住已知结果),这两种算法的复杂度都已经为 O(n)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-28
      • 1970-01-01
      • 1970-01-01
      • 2017-11-20
      • 1970-01-01
      • 2013-04-28
      • 2011-02-12
      • 2015-05-13
      相关资源
      最近更新 更多