【发布时间】:2016-08-12 20:43:30
【问题描述】:
运行时间、复杂度、编译时间和执行时间有什么区别? l 运行时间和时间复杂度有冲突,它们和执行时间有什么区别?
【问题讨论】:
标签: algorithm runtime complexity-theory
运行时间、复杂度、编译时间和执行时间有什么区别? l 运行时间和时间复杂度有冲突,它们和执行时间有什么区别?
【问题讨论】:
标签: algorithm runtime complexity-theory
您真正要问的是如何将 Big O 时间复杂度 转换为 runtime。这并不像一开始看起来那么容易。
所以先仔细看看复杂性,为了更简单,让我们使用这个简单的 C++ 示例:
int fact(int n)
{
if (n<=1) return 1;
return n*fact(n-1);
}
时间与空间复杂度
(对于初学者,我假设基本变量,因此所有复杂性都与基础相同,更多信息请参阅下一个项目符号)所以整个事情将执行 n 迭代,暗示 O(n) 时间复杂度。由于这对单个辅助结果使用堆栈递归和堆,空间复杂度也是O(n)。
基础复杂度与真实复杂度
基础复杂度是所用算法的复杂度。但是当实现到程序中时,由于变量实现、IO 协议等原因,复杂性可能会发生变化(变得更糟)。
例如,如果我们使用 bigint 代替 int 会怎样?该程序是相同的,因此基本复杂性保持O(n)。 bigints 的问题在于它们不是O(1) 空间复杂度(更像O(log(n)))并且对它们的操作也不再是O(1)。例如,如果 (m=log(n)) 则 (+,-,&,|,^) 操作为 O(m),则 mutliply 可以变化到 O(m^2)。因此,如果使用 O(m^2) 乘法,则时间复杂度将为 O(n.log(n).log(n))。空间复杂度也更差O(n.log(n))。
问题是大多数菜鸟只使用算法的基础复杂度,而不是实现的整体复杂度,导致结果晦涩难懂。现在的另一个问题是在没有任何背景知识的情况下滥用库和框架。
计算运行时
编程中的这种热有时被认为是矛盾的。没有可靠的方法可以将复杂性转换为任意实现的运行时。为什么?因为运行时依赖于太多的东西,比如:
展位空间和时间复杂性
现代架构使用流水线、超缩放、缓存等。因此,当您遇到空间障碍时,性能可能会变化很多倍,通常会变得更糟。
硬件平台
每个平台都不同。即使在类似功率的CPU之间进行比较,管道/缓存大小的配置、其管理策略、延迟等也会产生巨大的差异。在 HW 平台上不仅仅是 CPU。并且使用的每个模块都很重要(内存、HDD、DMA、gfx...)
编译器
每个编译器都有自己的怪癖、优化等,从而导致不同的汇编输出。这可能导致在不同编译器上编译的相同源代码的可执行文件之间存在巨大差异。
操作系统
操作系统运行的不仅仅是您的应用程序。有服务、中断、维护任务和其他进程,所有这些都会影响运行时。
编程风格
这也可以。大多数编程风格差异通常通过编译器优化来抵消,但不是全部。例如,迭代偏好之前的递归会对运行时产生巨大的(通常是负面的)影响。
优化
如果您在汇编中查看未优化的代码和优化的代码,您通常不会再识别这些代码。这不应该影响程序的基本复杂性,但如果可以的话,通常会改变真正的复杂性。
我也编码了几十年,所以我习惯于自己优化我的代码。这种偏好有时会误导现代编译器,并在极少数情况下导致生成的代码变慢。
那么如何计算 Runtime?
你不能做到最好的就是测量+估计。
t0在任务期间测量时间(不时)
例如每秒,或每1000th 迭代...记住时间t和迭代i。这有时称为经过时间。
预测剩余时间。
所以如果我们有时间复杂度O(n) 那么(如果我没记错的话):
t(0) = t0
t(i) = ti ~= t0 + T*i -> T ~= (ti-t0)/i
t(n) = t0+T*n ~= t0 + (ti-t0)*n/i
您可以在计算过程中平均或更新这个时间,这样每次新的测量都会越来越准确。有时也更好地从最近几次测量t(i) 和t(j) 评估运行时间,因为处理能力会随着时间而改变。
在高精度测量时间时注意操作系统粒度
如果不加以考虑,它可能会极大地误导您的计算。但这仅在您想测量非常快速的过程时才重要,而我认为并非如此。
附言。
这一切都只适用于足够大的n,否则从复杂性中丢弃的热量仍然很重要,并对结果的准确性产生负面影响。
编译时间
正如其他答案中提到的,这是编译器需要处理您的源代码的时间。这与程序的复杂性无关。这主要受包括递归级别、源代码长度、宏使用和递归、模板使用等影响。
通常通过简单地重新排序#include 并避免多次包含,您可以显着缩短编译时间。很好的例子是来自 Atmel 的 AVR32 框架……在调整这个之后,编译时间可以提高 100 倍甚至更多。一旦我看到(10 多年前)一个打印机固件,它有 300MB 的源代码(当时)并且由于包含滥用,编译时间比一个小时略短......考虑到它是单一的代码,这太疯狂了单片机...
希望对你有帮助
【讨论】:
a*n+c 是迭代次数而不是运行时。正如我试图解释的那样,运行时受到太多事物的影响,由此产生的多项式可能与基本复杂度有很大不同。如果您在没有丢弃任何较低渐近热值(即您认为的运行时复杂度)的情况下获得了真正的复杂性,那么您只能在没有旧架构的情况下从中计算运行时:流水线、超缩放、缓存、多线程、中断、IO 突发等。
n 很大),其中只有最大的渐近热很重要。必须测量恒定时间(您的 a,c)(也处于饱和状态),否则任何计算的时间都将不可靠。
n 仍然很小(即使代码中没有任何可疑之处)不一致主要是由于用于运行它的硬件架构造成的。
执行时间是您的程序执行所需的时间。例如,10 秒或 10 毫秒。
复杂性通常是指算法的渐近行为。简而言之,它表明 您的算法 是有效的。对此我们通常使用时间复杂度和空间复杂度。时间复杂度渐近地显示您的算法可以运行多快,而空间复杂度显示您的算法将使用多少位内存。这是使用大 O、小 o、Theta 等符号的地方。 (看 TimeComplexity)
运行时间可以与执行时间(程序终止所需的时间)互换使用。但是,通常当程序运行时发生一些错误时,它们通常也会通过运行时错误来引用它。
另外,编译时间是程序被编译并转换为可执行文件所需的时间。
【讨论】: