Algorithm 算法的效率

Algorithm 算法的效率,algorithm,Algorithm,我是计算机科学专业的学生,对算法一无所知。我们在课堂上学习算法的设计和分析课程。 我想知道为什么算法的时间复杂度是用 O(n),O(logn)等,并且不以秒或毫秒为单位测量实际时间?有助于讨论算法的理论方面。不讨论实际执行时间的主要原因是: 实际执行时间因硬件、输入大小和优化的不同而变化很大 它允许我们讨论和分析高执行时间甚至无限执行时间的算法 类分类,也称为Big-O表示法,在给定足够长的输入的情况下,无论其实现如何,都为我们提供了算法效率的有用描述。例如,对于足够长的输入,O(log(n)

我是计算机科学专业的学生,对算法一无所知。我们在课堂上学习算法的设计和分析课程。 我想知道为什么算法的时间复杂度是用
O(n)
O(logn)
等,并且不以秒或毫秒为单位测量实际时间?

有助于讨论算法的理论方面。不讨论实际执行时间的主要原因是:

  • 实际执行时间因硬件、输入大小和优化的不同而变化很大
  • 它允许我们讨论和分析高执行时间甚至无限执行时间的算法
  • 类分类,也称为Big-O表示法,在给定足够长的输入的情况下,无论其实现如何,都为我们提供了算法效率的有用描述。例如,对于足够长的输入,
    O(log(n))
    算法比
    O(n)
    算法更快,但对于较短的输入,后者可能更快
  • 这种讨论与语言无关,适用于任何软件体系结构

应始终考虑实际因素,但大O是每次讨论算法解决方案的基础。如果您不能对算法进行Big-O分析,那么您的代码将永远无法扩展。

执行单个指令的时间取决于硬件,而且由于算法是人工生成的,因此最好以该特定格式返回答案。大O定义最坏情况N表示块代码将执行的次数,其中N通常定义数组对象的元素数。

需要了解的一个关键问题是,这些复杂度类不是用来描述算法的实际执行时间的,而是描述最坏情况的执行时间

这一点很重要,因为一个递归算法,其复杂度等级为O(2^N),如果由于传递了一个参数,它实际上不必执行递归,那么它的执行可能与O(1)等效,但使用大O表示法,您并不是在描述算法的具体执行-同样,您正在描述算法的最坏执行情况


执行时间毫秒测量值测量的是另一种情况。Big-O表示法描述了上述算法的最坏情况,但它所采用的方式并不特定于它所运行的特定平台,而毫秒时间测量只能描述单个特定机器上的单个特定执行。在您的普通桌面系统上,尤其是在C#.NET或Java等托管语言上构建时,每次运行算法(如垃圾收集)时,都会出现一些可能导致波动的情况—测量函数执行所需的时间一刻可能为3毫秒,下一分钟可能为5毫秒。在一台速度更快的计算机上,可能只需要0.005毫秒——正如你所见,这样的测量很少告诉我们算法本身,这就是为什么你需要像Big-O这样的东西——它专门讨论算法,而不是在特定的时间在特定的系统上特定的执行该算法。

为什么不以秒/毫秒的实际时间来描述效率?

我们不这么做的原因有很多(其中一些是显而易见的):

  • 实际时间根据算法的实现而变化
  • 实际时间取决于编译器生成的代码(以及指定的所有优化选项)
  • 实际时间因时间共享、通信开销(分布式算法)等而变化
  • 实际时间取决于运行程序的系统配置(时钟速率、缓存大小、网络拓扑等)
  • 我们还想看看算法是如何随着问题的大小而扩展的。描述算法相对于问题大小的速度的函数更有用

为什么效率不被描述为输入大小的精确函数,并给出精确的运行时间?

  • 同样,系统的配置(系统架构、时钟速率、指令集等)
  • 同样,编译器对代码的优化可能会改变某些系数
  • 对于复杂的算法,或者精确的运行时间取决于输出的某些特征的算法,推导精确的公式可能并不容易
然后呢?

这就是为什么它被描述为属于一类函数

这样做的好处是,我们知道算法的可伸缩性(相对于输入大小),而无需深入了解实现或实际系统的细节。我们甚至可以描述一类算法(例如,对于基于比较的排序算法,ω(n logn))的最佳/最差时间复杂度


这样做的缺点是常数是隐藏的,只剩下最强大的项。2算法可能具有相同的时间复杂度,但一种算法可能比另一种算法更快,因为它具有较小的常数(Floyd循环查找算法与Brent循环查找算法)。一些具有巨大隐藏常数的算法只有在输入量非常大的情况下才有用。因此,不应仅根据时间复杂度选择算法,还需要考虑最大可接受输入大小。

实际时间在很大程度上取决于实现。根据时间来描述它是不现实的。您还希望将其与输入的大小联系起来。此问题应移至,您将发现许多有用的资源:)