Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 确定递归函数的复杂性(大O表示法)_Recursion_Big O_Complexity Theory - Fatal编程技术网

Recursion 确定递归函数的复杂性(大O表示法)

Recursion 确定递归函数的复杂性(大O表示法),recursion,big-o,complexity-theory,Recursion,Big O,Complexity Theory,明天我有一个计算机科学期中考试,我需要帮助确定这些递归函数的复杂性。我知道如何解决简单的案件,但我仍在努力学习如何解决这些较难的案件。这些只是我无法理解的几个示例问题。任何帮助都将不胜感激,并将对我的学习大有帮助,谢谢 int recursiveFun1(int n) { if (n <= 0) return 1; else return 1 + recursiveFun1(n-1); } int recursiveFun2(int n)

明天我有一个计算机科学期中考试,我需要帮助确定这些递归函数的复杂性。我知道如何解决简单的案件,但我仍在努力学习如何解决这些较难的案件。这些只是我无法理解的几个示例问题。任何帮助都将不胜感激,并将对我的学习大有帮助,谢谢

int recursiveFun1(int n)
{
    if (n <= 0)
        return 1;
    else
        return 1 + recursiveFun1(n-1);
}

int recursiveFun2(int n)
{
    if (n <= 0)
        return 1;
    else
        return 1 + recursiveFun2(n-5);
}

int recursiveFun3(int n)
{
    if (n <= 0)
        return 1;
    else
        return 1 + recursiveFun3(n/5);
}

void recursiveFun4(int n, int m, int o)
{
    if (n <= 0)
    {
        printf("%d, %d\n",m, o);
    }
    else
    {
        recursiveFun4(n-1, m+1, o);
        recursiveFun4(n-1, m, o+1);
    }
}

int recursiveFun5(int n)
{
    for (i = 0; i < n; i += 2) {
        // do something
    }

    if (n <= 0)
        return 1;
    else
        return 1 + recursiveFun5(n-5);
}
intrecursivefun1(intn)
{

如果(n每个函数的时间复杂度,用大O表示法:


此函数每次调用n-5,因此我们在调用函数之前从n中减去5,但n-5也是
O(n)
。 (实际称为n/5倍的顺序,并且,O(n/5)=O(n))


在这里,它是
O(2^n)
,或者指数的,因为每个函数调用自己两次,除非它被递归n次



int递归函数5(int n)
{
对于(i=0;i如果(n用于
n=0
的情况

我们将在下面的部分中考虑案例<代码> n>=0 < /> >

一,

其中a是常数

通过归纳法:

T(n) = n * a + T(0) = n * a + b = O(n)
T(n) = ceil(n / 5) * a + T(k) = ceil(n / 5) * a + b = O(n)
T(n) = a * log5(n) + T(0) = a * log5(n) + b = O(log n)
T(n) = a + 2a + 4a + ... + 2^(n-1) * a + T(0) * 2^n 
     = a * 2^n - a + b * 2^n
     = (a + b) * 2^n - a
     = O(2 ^ n)
T(n) = T(5q + r)
     = (5q + r) / 2 + (5 * (q - 1) + r) / 2 + ... + r / 2 +  T(r)
     = 5 / 2 * (q + (q - 1) + ... + 1) +  1 / 2 * (q + 1) * r + T(r)
     = 5 / 4 * (q + 1) * q + 1 / 2 * (q + 1) * r + T(r)
     = 5 / 4 * q^2 + 5 / 4 * q + 1 / 2 * q * r + 1 / 2 * r + T(r)
其中a,b是常数

二,

其中a是常数

通过归纳法:

T(n) = n * a + T(0) = n * a + b = O(n)
T(n) = ceil(n / 5) * a + T(k) = ceil(n / 5) * a + b = O(n)
T(n) = a * log5(n) + T(0) = a * log5(n) + b = O(log n)
T(n) = a + 2a + 4a + ... + 2^(n-1) * a + T(0) * 2^n 
     = a * 2^n - a + b * 2^n
     = (a + b) * 2^n - a
     = O(2 ^ n)
T(n) = T(5q + r)
     = (5q + r) / 2 + (5 * (q - 1) + r) / 2 + ... + r / 2 +  T(r)
     = 5 / 2 * (q + (q - 1) + ... + 1) +  1 / 2 * (q + 1) * r + T(r)
     = 5 / 4 * (q + 1) * q + 1 / 2 * (q + 1) * r + T(r)
     = 5 / 4 * q^2 + 5 / 4 * q + 1 / 2 * q * r + 1 / 2 * r + T(r)
其中a,b是一些常数,k=T(r)


我找到的逼近递归算法复杂度的最佳方法之一是绘制递归树。一旦有了递归树:

Complexity = length of tree from root node to leaf node * number of leaf nodes
  • 第一个函数的长度为
    n
    ,叶节点数为
    1
    ,因此复杂性为
    n*1=n
  • 第二个函数的长度为
    n/5
    ,叶节点的数量为
    1
    ,因此复杂性为
    n/5*1=n/5
    。应近似为
    n

  • 对于第三个函数,因为在每次递归调用中,
    n
    被除以5,递归树的长度将是
    log(n)(以5为基数)
    ,叶节点的数量再次为1,因此复杂性将是
    log(n)(以5为基数)*1=log(n)(以5为基数)

  • 对于第四个函数,因为每个节点都有两个子节点,所以叶节点的数量将等于
    (2^n)
    ,递归树的长度将是
    n
    ,因此复杂性将是
    (2^n)*n
    。但是因为
    n
    (2^n)之前是不重要的
    ,它可以被忽略,复杂性只能说是
    (2^n)

  • 对于第五个函数,有两个元素引入复杂性。每个函数中函数的递归性质引入的复杂性和
    For
    循环引入的复杂性。进行上述计算时,函数的递归性质引入的复杂性将是
    ~n
    和For循环引起的复杂性<代码>n
  • 。总的复杂性将是
    n*n


    注意:这是一种计算复杂性的快速而肮脏的方法(不是官方的!)。我很乐意听到有关这方面的反馈。谢谢。

    我们可以从数学上证明这一点,这是我在上述答案中遗漏的

    它可以大大帮助您理解如何计算任何方法。 我建议从头到尾阅读,以充分了解如何做到这一点:

  • T(n)=T(n-1)+1
    这意味着方法完成所需的时间与相同的方法相同,但n-1是
    T(n-1)
    ,我们现在添加
    +1
    ,因为它是完成一般操作所需的时间(除了
    T(n-1)
    )。
    现在,我们将发现
    T(n-1)
    如下:
    T(n-1)=T(n-1)+1
    。看起来我们现在可以形成一个函数,它可以给我们一些重复,这样我们就可以完全理解了。我们将把
    T(n-1)=…
    的右侧,而不是
    T(n-1)
    放在方法
    T(n)中=…
    这将给我们:
    T(n)=T(n-1-1)+1+1
    这是
    T(n)=T(n-2)+2
    ,或者换句话说,我们需要找到我们缺少的
    k
    T(n)=T(n-k)+k
    。下一步是采取
    n-k
    ,并声称
    n-k=1
    ,因为在递归结束时正好需要O(1)当
    n时,这里的关键是可视化调用树。一旦这样做,复杂性是:

    nodes of the call tree * complexity of other code in the function
    
    后一项的计算方法与我们对正规迭代函数的计算方法相同

    相反,完整树的总节点计算为

                      C^L - 1
                      -------  , when C>1
                   /   C - 1
                  /
     # of nodes =
                  \    
                   \ 
                      L        , when C=1
    
    其中C是每个节点的子节点数,L是树的级别数(包括根)

    可视化树很容易。从第一次调用(根节点)开始,然后绘制与函数中递归调用数相同的子级数。将传递给子调用的参数作为“节点值”写入也很有用

    因此,在上面的例子中:

  • 这里的调用树是C=1,L=n+1。其余函数的复杂度是O(1)。因此,总复杂度是L*O(1)=(n+1)*O(1)=O(n)
  • 这里的调用树是C=1,L=n/5。函数其余部分的复杂度是O(1)。因此总复杂度是L*O(1)=(n/5)*O(1)=O(n)
  • 这里的调用树是C=1,L=log(n)。函数其余部分的复杂度是O(1)。因此,总复杂度是L*O(1)=log5(n)*O(1)=O(log(n))
  • 这里的调用树是C=2,L=n。函数其余部分的复杂性是O(1)。 这次我们使用调用树中节点数的完整公式,因为C>1。因此总复杂度为(C^L-1)/(C-1)*O(1)=(2^n-1)*O(1)=O(2^n)
  • 这里的调用树是C=1,L=n/5。函数其余部分的复杂度是O(n)。因此,总复杂度是L*O(1)=(n/5)*O(n)=O(n^2)

  • 我看到了公认的答案(重复
    T(n) = n / 2 + T(n - 5)
    
    T(5q + r) = (5q + r) / 2 + T(5 * (q - 1) + r)
    
    T(n) = T(5q + r)
         = (5q + r) / 2 + (5 * (q - 1) + r) / 2 + ... + r / 2 +  T(r)
         = 5 / 2 * (q + (q - 1) + ... + 1) +  1 / 2 * (q + 1) * r + T(r)
         = 5 / 4 * (q + 1) * q + 1 / 2 * (q + 1) * r + T(r)
         = 5 / 4 * q^2 + 5 / 4 * q + 1 / 2 * q * r + 1 / 2 * r + T(r)
    
    T(n) = T(5q + r)
         = 5 / 2 * q^2 + (5 / 4 + 1 / 2 * r) * q + 1 / 2 * r + b
         = 5 / 2 * O(n ^ 2) + (5 / 4 + 1 / 2 * r) * O(n) + 1 / 2 * r + b
         = O(n ^ 2)
    
    Complexity = length of tree from root node to leaf node * number of leaf nodes
    
    nodes of the call tree * complexity of other code in the function
    
                      C^L - 1
                      -------  , when C>1
                   /   C - 1
                  /
     # of nodes =
                  \    
                   \ 
                      L        , when C=1
    
    n     level 1
    n-1   level 2
    n-2   level 3
    n-3   level 4
    ... ~ n levels -> L = n
    
    n
    n-5
    n-10
    n-15
    ... ~ n/5 levels -> L = n/5
    
    n
    n/5
    n/5^2
    n/5^3
    ... ~ log5(n) levels -> L = log5(n)
    
                   n                   level 1
          n-1             n-1          level 2
      n-2     n-2     n-2     n-2      ...
    n-3 n-3 n-3 n-3 n-3 n-3 n-3 n-3    ...     
                  ...                ~ n levels -> L = n
    
    n
    n-5
    n-10
    n-15
    ... ~ n/5 levels -> L = n/5