【问题标题】:Differences between time complexity and space complexity?时间复杂度和空间复杂度的区别?
【发布时间】:2013-09-12 05:27:05
【问题描述】:

我已经看到,在大多数情况下,时间复杂度与空间复杂度有关,反之亦然。例如在数组遍历中:

for i=1 to length(v)
    print (v[i])
endfor

这里很容易看出算法复杂度在时间上是O(n),但在我看来空间复杂度也是n(也表示为O(n)?)。

我的问题:算法的时间复杂度是否可能与空间复杂度不同?

【问题讨论】:

  • 谢谢,这有助于我理解复杂性中的一些基本知识
  • 我在某处听到过这样的一句话:“在有限的时间内,一个人只能写入有限的内存,但你只需要非常有限的内存就可以永远迭代它”
  • @codor 是的,人们经常听到非常愚蠢的事情。
  • @AndreaAsperti 感谢您的评论;但我在这里错过了一些讽刺吗?尽管有公认的书呆子措辞,但这是真的,不是吗?
  • @codor 不,正如我在回答中解释的那样。可以检测到这种循环:您知道您正在循环,因此您可以停止计算。

标签: algorithm complexity-theory big-o


【解决方案1】:

timespace 复杂性彼此不相关。它们用于描述您的算法根据输入占用多少空间/时间。

  • 例如当算法的空间复杂度为:

    • O(1) - 常量 - 算法使用不依赖于输入的固定(少量)空间。对于输入的每个大小,算法将占用相同(恒定)的空间量。在您的示例中就是这种情况,因为没有考虑输入,重要的是 print 命令的时间/空间。
    • O(n)O(n^2)O(log(n))... - 这些表示您根据输入的长度创建其他对象。例如,创建v 的每个对象的副本,将其存储在一个数组中,然后在创建n 其他对象时占用O(n) 空间。
  • 相比之下,时间复杂度描述了您的算法根据输入的长度消耗了多少时间。再次:

    • O(1) - 无论输入有多大,它总是需要一个恒定的时间 - 例如只有一条指令。喜欢

      function(list l) {
          print("i got a list");
      }
      
    • O(n), O(n^2), O(log(n)) - 同样基于输入的长度。例如

      function(list l) {
           for (node in l) {
              print(node);
          }
      }
      

请注意,最后两个示例都占用了O(1) 空间,因为您没有创建任何内容。比较它们

function(list l) {
    list c;
    for (node in l) {
        c.add(node);
    }
}

它占用了O(n) 空间,因为您创建了一个新列表,其大小以线性方式取决于输入的大小。

您的示例表明时间和空间复杂度可能不同。打印所有元素需要v.length * print.time。但是空间总是一样的——O(1),因为你不创建额外的对象。所以,是的,一个算法有可能具有不同的时间和空间复杂度,因为它们并不相互依赖。

【讨论】:

  • O(1) 并不意味着固定或恒定,它意味着有界。例如,采用列表并对前多达 1 万亿个元素进行冒泡排序的函数在时间和空间复杂度上为 O(1),但执行的比较次数从 0 到 5e23 不等。即使您将输入限制为大型列表,运行时间也会从 1e12 变化到 5e23。
  • 而不是调用O(1)一个常量,id说它表示占用的空间与输入大小无关。
  • @LoveMeow 这也是错误的。我最多可以记住一个数组的 100 个第一个元素。那么占用的空间是 O(1) 但与输入大小无关。
  • 同意 Aviad,这个答案是错误的。时间和空间复杂度是相互关联的。
  • @AndreaAsperti 请解释一下?
【解决方案2】:

时间和空间复杂度是计算算法效率的不同方面。

时间复杂度处理找出计算时间如何 算法会随着输入大小的变化而变化。

另一方面,空间复杂度处理的是找出多少 算法将需要(额外)空间,而 输入大小。

计算算法的时间复杂度最好的方法是检查我们是否增加输入的大小,比较(或计算步骤)的数量是否也会增加,计算空间复杂度最好的办法是查看额外的算法的内存需求也随着输入大小的变化而变化。

Bubble sort 就是一个很好的例子。

假设您尝试对包含 5 个元素的数组进行排序。 在第一遍中,您将比较第一个元素与接下来的 4 个元素。在第二遍中,您将比较第二个元素与接下来的 3 个元素,您将继续此过程,直到您完全用完列表。

现在如果您尝试对 10 个元素进行排序会发生什么。在这种情况下,您将首先将第一个元素与接下来的 9 个元素进行比较,然后将第二个元素与接下来的 8 个元素进行比较,依此类推。换句话说,如果您有 N 个元素数组,您将首先将第一个元素与 N-1 个元素进行比较,然后将第二个元素与 N-2 个元素进行比较,依此类推。这导致O(N^2) 时间复杂度。

但是尺寸呢?当您对 5 个元素或 10 个元素的数组进行排序时,您是否使用了任何额外的缓冲区或内存空间。你可能会说是的,我确实使用了一个临时变量来进行交换。但是,当您将数组的大小从 5 增加到 10 时,变量的数量是否发生了变化。不,无论输入的大小是多少,您都将始终使用单个变量来进行交换。好吧,这意味着输入的大小与您需要的额外空间无关,从而导致O(1) 或恒定的空间复杂度。

现在作为一个练习,研究merge sort的时间和空间复杂度

【讨论】:

    【解决方案3】:

    首先,这个循环的空间复杂度是O(1)(在计算算法需要多少存储空间时,通常不包括输入)。

    所以我的问题是,算法是否有可能具有与空间复杂度不同的时间复杂度?

    是的,是的。一般来说,算法的时间复杂度和空间复杂度是没有关系的。

    有时可以以牺牲另一个为代价来增加一个。这称为space-time tradeoff

    【讨论】:

    • 你能分享一些例子吗? @NPE
    • 一个常见的假设是空间不能比时间差,因为启动分配内存的工作随着分配大小而增长。
    • @smossen:很好的观察!
    • @smossen 把它放在答案中怎么样?
    【解决方案4】:

    时间和空间复杂度之间存在众所周知的关系。

    首先,时间显然与空间消耗有关:在时间 t 你不能到达超过 O(t) 个内存单元。这通常表示 通过包含

                                DTime(f) ⊆ DSpace(f)
    

    其中 DTime(f) 和 DSpace(f) 是语言集 可被确定性图灵机及时识别 (分别为空间)O(f)。也就是说,如果一个问题可以 在时间 O(f) 中求解,那么也可以在空间 O(f) 中求解。

    不太明显的是,空间提供了时间的界限。认为 即,在大小为 n 的输入上,您可以使用 f(n) 个存储单元, 包括寄存器、缓存和一切。写完这些单元格后 在所有 可能 方式你最终可能会停止你的计算, 因为否则你会重新输入你的配置 已经通过,开始循环。现在,在二进制字母表上, f(n) 个单元格可以用 2^f(n) 种不同的方式编写,这给出了我们的 时间上限:计算将在此范围内停止, 或者你可以强制终止,因为计算永远不会停止。

    这通常在包含中表达

                              DSpace(f) ⊆ Dtime(2^(cf))
    

    对于一些常数 c。常数 c 的原因是,如果 L 在 DSpace(f) 中,你只 知道它将在空间 O(f) 中被识别,而在前一个 推理, f 是一个实际的界限。

    以上关系被更强的版本所包含,涉及 计算的不确定性模型,这就是它们的方式 教科书中经常提到的(参见例如计算中的定理 7.4 Papadimitriou 的复杂性)。

    【讨论】:

    • 但是如果您实际上不知道您访问了多少个州,您如何强制在 $2^f(n)$ 终止?
    • @SenorBilly 其实不需要计算也不需要强制终止。您知道机器将在该时间范围内停止,否则它将处于循环中(并且它不能循环,否则空间消耗将是不确定的,因为它是在计算结束时测量的)。
    【解决方案5】:

    是的,这绝对是可能的。例如,对n 实数进行排序需要O(n) 空间,但需要O(n log n) 时间。确实,空间复杂度始终是时间复杂度的下界,因为初始化空间的时间包含在运行时间中。

    【讨论】:

    • 通常空间复杂度描述了算法需要的额外空间,排序可以使用 O(1)(额外)空间(因此不需要 O(n) 空间)。而且我认为您必须在这里使用空间复杂度的“额外空间”定义,因为否则您会说排序数组的二进制搜索需要 O(n) 空间并在 O(log n) 时间内运行,这与您关于时间复杂度总是主导空间复杂度。
    【解决方案6】:

    有时是的,它们是相关的,有时不是,它们是不相关的, 实际上,我们有时会使用更多空间来获得更快的算法,例如动态编程https://www.codechef.com/wiki/tutorial-dynamic-programming 动态编程使用记忆或自底向上,第一种技术使用记忆来记住重复的解决方案,因此算法不需要重新计算它,而只需从解决方案列表中获取它们。自下而上的方法从小解决方案开始,并在此基础上达到最终解决方案。 这里有两个简单的例子,一个显示时间和空间的关系,另一个显示没有关系: 假设我们想要找到从 1 到给定 n 整数的所有整数的总和: 代码1:

    sum=0
    for i=1 to n
       sum=sum+1
    print sum
    

    这段代码只使用了内存中的 6 个字节 i=>2,n=>2 和 sum=>2 个字节 因此时间复杂度为 O(n),而空间复杂度为 O(1) 代码2:

    array a[n]
    a[1]=1
    for i=2 to n
        a[i]=a[i-1]+i
    print a[n]
    

    此代码至少使用了内存中的 n*2 字节用于数组 因此空间复杂度是O(n),时间复杂度也是O(n)

    【讨论】:

      【解决方案7】:

      算法所需的存储空间量随其解决的问题的大小而变化。空间复杂度通常表示为一个数量级,例如O(N^2) 意味着如果问题的大小 (N) 翻倍,则需要四倍的工作存储空间。

      【讨论】:

        猜你喜欢
        • 2012-08-14
        • 1970-01-01
        • 2016-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-02
        相关资源
        最近更新 更多