如何确定算法的内存和时间复杂度?

时间:2013-12-27 02:05:44

标签: algorithm time-complexity space-complexity

我不擅长确定时间和记忆的复杂性,如果有人可以帮助我,我会很感激。

我有一个算法,在这里,我不确定它的时间和记忆复杂性是什么。

Function sample(k)
   IF k < 2
       Return 0
   Return 1 + sample(k/2)

它的时间和内存复杂性是什么?为什么?

由于

2 个答案:

答案 0 :(得分:19)

确定时间和内存复杂性等于计算运行算法时使用了多少这两种资源,并查看这些数量如何随输入大小而变化( k 在这种情况下)改变。

时间将取决于每条指令的评估次数,空间将取决于计算解决方案所需的数据结构的大小。

在这个特定的场景中,你正在看一个递归算法,所以基本上这涉及计数1)进行了多少递归调用,以及2)为每个调用完成了多少工作。

由于每次调用输入减半,调用序列将如下所示:

sample(k)       )
 sample(k/2)    )
  sample(k/4)   ) 
     ...        ) - n = number of calls 
    sample(4)   )
     sample(2)  )
      sample(1) )

以这种方式减少每次递归调用会导致对数次调用。

n = log(k)

在每次调用时,我们在调用堆栈中存储常量数量的变量,并执行一定量的工作(操作)。这源于这样一个事实:每次调用中的变量数量和比较/加法/除法不会随着 k 更大而变大。

总时间复杂度是呼叫次数乘以每次呼叫完成的工作量,因此

time complexity = A*log(k) + B

对于某些常量A和B,它们分别反映了进行递归调用和进行比较/除法的实际时间成本。同样:

space complexity = C*log(k) + D

对于适当的常数C和D,分别表示递归和变量存储的空间成本。

现在在这种分析中,我们主要关注的是渐近复杂度,即我们并不关心常量,因为它们反映了运行算法的机器的细节,我们真的想知道它的形状曲线( k 变大)。如果您遵循使用Big-Oh表示法编写复杂性的规则,您将得出结果:

space complexity = time complexity = O(log(k))

编辑:内存复杂性细节

正如我之前所说,内存复杂性取决于数据结构计算解决方案所需的大小,因此您可能会问:此函数中没有使用数据结构,因此log(k)在哪里记忆力去了吗?

简答:您必须存储log(k)个参数k的不同值,每个递归调用一个。

详细解答:函数调用机制(我们通过递归利用)在这里使用隐式数据结构,其名称为 call stack 的。每次调用sample(k)时,都会创建一个新的堆栈帧,并将许多值压入堆栈:参数k的本地值,返回地址和其他依赖于实现的内容。以这种方式,每个递归调用在堆栈上形成存储其本地信息的“层”。整个画面最终看起来像这样:

----------- < top of stack
|  k = 1  |
|   ...   | < stack frame for sample(1)
|---------|
|  k = 2  |
|   ...   | < stack frame for sample(2)
|---------|

    ...

|---------|
| k = p/2 |
|   ...   | < stack frame for sample(p/2)
|---------|
|  k = p  |
|   ...   | < stack frame for sample(p)
|---------|
|         | < stack frame for main() or whatever 
              initially called sample(p) 
              (we don't count this one)

(我在这里区分了每次递归调用时p的值的初始参数值k,以避免混淆,希望如此)

需要注意的是,由于存在n = log(k)递归调用,因此存在n个堆栈帧。每个堆栈帧具有恒定的大小,因此空间复杂度为O(log(k))

答案 1 :(得分:0)

你真的在看log_2(k),以2为底的对数。要改变基数,你必须乘以常数。而且由于我们无论如何都乘以常数,O(log(n)),O(ln(n))和O(log_2(n))都是相同的。

那么为什么上述方法与base 2具有对数复杂度?你在每次通话时将k分成两半。如果你倒退,你会在每次通话时乘以2。乘以2是2 ^ n,log_2(n)正好相反。

如果你绘制一个二叉树,它可能会有所帮助:一个有n个节点的树的高度为log_2(n),一个高度为n的树有2 ^ n个节点。