递归时间复杂度定义混乱

时间:2019-06-18 14:17:52

标签: recursion time-complexity

递归算法的时间复杂度据说是

Given a recursion algorithm, its time complexity O(T) is typically 
the product of the number of recursion invocations (denoted as R) 
and the time complexity of calculation (denoted as O(s)) 
that incurs along with each recursion 
O(T) = R * O(s)

查看递归函数:

void algo(n){
  if (n == 0) return; // base case just to not have stack overflow
  for(i = 0; i < n; i++);// to do O(n) work 
  algo(n/2);
}

根据上面的定义,我可以说,时间复杂度是,R是logn倍,O(s)是n。因此,结果应为n logn,其中与数学归纳法一样,证明了结果在o(n)中。

请不要证明归纳方法。我在问为什么给定的定义不适用于我的方法。

2 个答案:

答案 0 :(得分:2)

好问题!这用两种不同的方式来计算递归调用链中完成的工作量。

您描述的用于计算递归调用中完成的工作量的原始策略(将每个调用完成的工作量乘以调用数)具有一个隐式假设。也就是说,这假设每个递归调用所做的工作量都是相同的。如果确实如此,那么您可以将完成的总工作量确定为调用次数和每个调用的工作量的乘积。

但是,如果每个调用完成的工作量随调用参数的变化而变化,则此策略通常不起作用。毕竟,如果没有一个表示完成多少工作的值,我们就谈不上将一个呼叫完成的“工作量”乘以调用次数!

确定递归调用链完成多少工作的更通用策略是合计每个单独的递归调用完成的工作量。对于上面概述的函数,第一次调用完成的工作是n。第二个调用执行n / 2次工作,因为它所做的工作量在其参数中是线性的。第三个调用执行n / 4个工作,第四个调用n / 8个工作,依此类推。这意味着完成的总工作受

限制
  

n + n / 2 + n / 4 + n / 8 + n / 16 + ...

     

= n(1 + 1/2 + 1/4 + 1/8 + 1/16 + ...)

     

≤2n,

这是更严格的O(n)限制的来源。

请注意,在特定情况下,“将所有呼叫完成的所有工作加起来”的想法完全等同于“每个呼叫完成的工作量乘以呼叫数量”。每个调用完成的是相同的。你知道为什么吗?

或者,如果您可以确定递归调用链完成的工作量的保守上限,则可以将调用次数乘以任意一次调用的最大个工作。那将永远不会低估总数,但是它不会总是给您正确的界限。这就是您所列出的示例中发生的情况-每个调用最多完成n个工作,并且有O(log n)个调用,因此总工作量确实为O(n log n)。但这并不是偶然的。

快速注释-我认为将总工作量乘以调用次数的策略称为递归调用链完成的工作量的“定义”是不合适的。如上所述,与其说是正式的定义,不如说是一种“确定完成工作的策略”。如果有的话,我认为正确的正式定义应该是“每个递归调用完成的工作量之和”,因为这样可以更准确地说明将花费多少总时间。

希望这会有所帮助!

答案 1 :(得分:0)

我认为您正在尝试查找有关主定理的信息,该信息用于证明递归算法的时间复杂性。

https://en.wikipedia.org/wiki/Master_theorem_(analysis_of_algorithms)

此外,通常不能仅通过查看算法来确定算法运行时,尤其是递归算法。这就是为什么您的快速分析与归纳证明不同的原因。