【问题标题】:What is the general way to find space complexity of recursive algorithms?查找递归算法的空间复杂度的一般方法是什么?
【发布时间】:2016-09-28 16:29:38
【问题描述】:
int factorial(int n)
{
    if(n < 0)  {return -1;}
    if(n == 0) {return  1;}
    return n*factorial(n-1);
}

为了找到时间复杂度,我创建了一个递归关系

T(n) = T(n-1) + c = T(n-2) + 2c = ... = T(n-k) + kc => O(n)
T(0) = 1;

为这类算法(如斐波那契)找到空间复杂度的一般方法是什么?我们需要找到调用堆栈的深处吗?

【问题讨论】:

  • 那么你将不得不递归调用它n次,每次调用都会在堆栈上分配自己的带有局部变量的帧,所以空间复杂度是n的顺序。
  • 每次调用factorial 函数都会在内存的“堆栈”部分为该调用创建一个堆栈帧。单个堆栈帧将包含此函数中定义的变量、函数中的参数和返回地址。在这种情况下,对于每个呼叫,可以在恒定时间内存储此信息。由于此函数的调用次数是线性的,因此总内存将为 O(n)。

标签: c# algorithm big-o


【解决方案1】:

递归算法所需的空间可以近似为三个元素。存储所需空间

  • 递归堆栈
  • 您输入函数的参数
  • 函数的输出

以阶乘为例。递归公式为T(n) = T(n-1) + c。展开它时,您会得到T(n) = T(n-1) + T(n-2) + ... + n c。所以递归堆栈需要O(n) 空间。

函数的输出将是n!,要存储一个数字n,您需要log(n) 位。因此,要存储结果,您需要log(n!) = O(n log n) 空间。

在递归的每个步骤中,您需要存储 1 个参数 (n)。您需要将其存储n 次,并且每个参数占用log(n) 空间。所以总共O(nlogn)

所以你最终得到了O(n) + O(nlogn) + O(nlogn) = O(nlogn)。这是计算阶乘递归所需的空间。


通过此分析,您可以找到为什么进行 alpa-beta 修剪的国际象棋程序需要大量 ram 才能正确计算位置。

【讨论】:

  • 我理解你的解释,但为什么其他人都说空间复杂度是 O(n)?
  • @ivan_petrushenko 问他们需要多少空间来存储一个数字n!。让我们选一个小数字n,比如5000。他们会说是O(1)吗?
  • 是的。对于n 的较大值,空间复杂度将不是线性的,时间复杂度也是如此(我猜),因为在@987654336 中,将两个非常大的数字相乘不能被视为常数时间运算 @。我写了O(n),因为我想当然地认为既然OP使用的是int,那么它就不能存储大于19!的数字。
【解决方案2】:

将时间复杂度写成这样的形式

T(n) = T(n - 1) + n

T(n) = 2T(n/2) + nlogn

等等。

你有两个选择:

1) 使用重复替换法,这在某些情况下需要一些数学技能,因为您应该按照步骤直到 T(1) 或 T(0),然后计算总和。

2) 使用类似于公式Master Theorem 的主定理,适用于许多实际案例

【讨论】:

    猜你喜欢
    • 2015-05-13
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多