了解这两个缩放属性之间的区别

时间:2018-11-25 22:41:04

标签: algorithm performance big-o scaling

我需要帮助来了解有关算法的书中的以下段落-

  

针对自然组合问题的搜索空间趋于增长   输入的大小N呈指数形式;如果输入大小增加   可能性增加一倍。星期三   像解决这类问题的好算法一样,具有更好的缩放比例   属性:当输入大小增加一个常数时,例如,   因数2-算法仅应减慢某个常数   因素C。

我真的不明白为什么一个要比另一个更好。如果有人可以提出任何示例来帮助我理解,将不胜感激。

1 个答案:

答案 0 :(得分:0)

让我们考虑以下问题:给您一个数字列表,并且您想要找到该列表中最长的子序列,其中数字按升序排列。例如,给定序列

2  7  1  8  3  9  4  5  0  6

您可以形成以下子序列[2,7,8,9]:

2  7  1  8  3  9  4  5  0  6
^  ^     ^     ^

但是这里还有一个更长的[1、3、4、5、6]:

2  7  1  8  3  9  4  5  0  6
      ^     ^     ^  ^     ^

我相信,这恰好是最长的子序列,其顺序是递增的,但是如果我记错了,请告诉我。

现在我们遇到了这个问题,在您有n个数字的一​​般情况下,我们将如何解决呢?让我们从一个不太好的选择开始。一种可能性是列出原始数字列表的所有子序列,然后过滤掉所有不按升序排列的内容,然后从我们发现的所有内容中选出最长的一个。例如,给出以下简短列表:

2  7  1  8

我们将形成所有可能的子序列,如下所示:

  • []
  • [8]
  • [1]
  • [1,8]
  • [7]
  • [7,8]
  • [7,1]
  • [7,1,8]
  • [2]
  • [2,8]
  • [2,1]
  • [2,1,8]
  • [2,7]
  • [2,7,8]
  • [2,7,1]
  • [2,7,1,8]

很喜欢,这个名单很长。但是,通过观察,我们可以看到增长最快的子序列的长度为2,并且有很多选择可供我们选择。

现在,随着我们的输入列表越来越长,这种扩展的效果如何?这是您要考虑的问题-这个新列表有多少个子序列,我是在现有列表的末尾加3来制成的?

2  7  1  8  3

嗯,每个现有的子序列在这里仍然是完全有效的子序列。但最重要的是,我们可以形成一堆新的子序列。实际上,我们可以采用任何现有的子序列,然后在其末尾添加3。这意味着,如果我们的长度为4的列表具有S个子序列,长度为5的列表将具有2S子序列。

更一般地说,您可以看到,如果您列出一个列表并在其末尾添加一个元素,则可以将可用子序列的数量加倍。这是一个数学事实,它本身并没有好坏之分,但是,如果我们要进行列出所有这些子序列并检查每个子序列以查看其是否具有某些特性,那么我们麻烦重重,因为这意味着将会有大量的子序列。我们已经看到四元素列表中有16个子序列。也就是说,五元素列表包含32个子序列,六元素列表包含64个子序列,更一般地说,n元素列表包含2 n 个子序列。

有了这些见解,让我们快速进行计算。我们将要检查多少个子序列,例如是否有300个元素的列表?我们可能必须检查其中的2 300 -这个数字大于可观察的宇宙中的原子数!哎呀。这将花费比我们更多的时间。

另一方面,有一个名为patience sorting的漂亮算法,它将总是找到最长的增长子序列,而且这样做很容易。您可以通过玩一个小游戏来做到这一点。您将把列表中的每个项目放入许多堆中的一个。要确定选择哪个桩,请寻找第一个桩的顶部编号大于所讨论的编号,并将其放在顶部。如果您找不到这种方式的桩,请将数字放在最右边的自己的桩中。

例如,给出此原始列表:

2  7  1  8  3  9  4  5  0  6

玩完游戏后,我们最终会遇到以下问题:

0
1    3    4    5
2    7    8    9    6

这是一个令人惊讶的事实:使用的桩数等于最长的增长子序列的长度。此外,您可以通过以下方式找到该子序列:每次将数字放在顶部记下一个桩的编号,记下桩顶部左侧的数字。如果我们使用以上数字进行操作,则会发现以下内容;括号内的数字告诉我们放下数字时堆栈顶部的内容是什么:

0
1     3 (1)    4 (3)    5 (4)
2     7 (2)    8 (7)    9 (8)    6 (5)

要找到所需的子序列,请从最左边的桩的顶部开始。写下该数字,然后找到括号中的数字并重复此过程。这样做在这里得到6、5、4、3、1,如果反向,则是最长的递增子序列1、3、4、5、6! (哇!)您可以证明这在所有情况下都有效,并且实际去做是一个非常漂亮的练习。

所以现在的问题是这个过程有多快。将第一个数字放下来需要一个工作单元-只需将其放在自己的堆中即可。放下第二个数字最多需要两个工作单元-我们必须看一下第一堆的顶部,然后选择将数字放到第二个堆中。放置第三个数字最多需要三个工作单元-我们必须查看最多两堆,并且可能将数字放入自己的第三堆中。通常,将第k个数字放下来需要k个工作单位。总的来说,这意味着我们正在做的工作大概是

  

1 + 2 + 3 + ... + n

如果我们有n个元素。那是一个著名的和,称为高斯和,它简化为大约n 2 /2。因此,可以说我们需要做大约n 2 / 2个单位用这种方式解决问题。

与之前的2 n 解决方案相比,它又如何呢?好吧,不像2 n 作为n的函数快速增长,n 2 / 2实际上是一个非常好的函数。如果我们插入n = 300,这之前在2 n 土地中返回了“宇宙中的原子数”,那么我们得到的则为45,000。如果那是十亿分之一秒,那不算什么。一秒钟之内就可以完成一台计算机。实际上,在查看将花费相当长的时间才能完成计算机的操作之前,必须插入相当大的n值。

与2 n 相比,函数n 2 / 2具有有趣的属性。如前所述,使用2 n ,如果将n加1,则2 n 将翻倍。另一方面,如果将n 2 / 2乘以n,则n 2 / 2会变大,但不会变大(具体来说,是n + 1/2)。

相比之下,如果您先取2 n ,然后 double n,则大小为2 n squares -y!但是,如果您将n 2 / 2乘以n,则n 2 / 2只会增加四倍-其实还不错,因为我们加倍了我们的输入大小!

这成为您提到的报价的核心。运行时间为2 n ,n!等的算法会随着n的变化严格地缩放 ,因为将n加1会导致巨大跳转在运行时。另一方面,n,n log n,n 2 等函数具有以下属性:如果将n加倍,则运行时只会增加某个常数项。因此,它们可以更好地根据输入进行缩放。