我的一个数据结构和算法问题是分析汇编代码并计算它的时间复杂度。我只是不理解我教授给我的例子。
将C代码转换为汇编指令C代码是:
int main(void)
{
int a[] = {11,-22,33}, length = 3, count = 0;
for (int i = 0 ; i < length ; i++)
if (a[i] > 5)
count++;
}
汇编代码是:
main:
pushq %rbp
movq %rsp, %rbp
movl $11, -32(%rbp)
movl $-22, -28(%rbp)
movl $33, -24(%rbp)
movl $3, -12(%rbp)
movl $0, -4(%rbp)
movl $0, -8(%rbp)
.L4:
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
jge .L2
movl -8(%rbp), %eax
cltq
movl -32(%rbp,%rax,4), %eax
cmpl $5, %eax
jle .L3
addl $1, -4(%rbp)
.L3:
addl $1, -8(%rbp)
jmp .L4
.L2:
movl $0, %eax
popq %rbp
ret
他的解释是:
最佳案例:指令数= 2 + n + 3 + 3(n + 1)+ 5n + 0 + 2n + 3 = 11n + 11
最坏情况:将0替换为n以获得指令数= 12n + 11
他的粗略解释是:
因为我们都近似并且也忽略了实际常数(例如11 * t0),所以更容易推理如下。 循环执行n次,循环内容占用恒定时间,因此总时间为O(n)。 大多数时候我们只使用粗略分析,这可以通过详细分析来证明。
我不明白这个解释。有人能更好地向我解释这个吗?
答案 0 :(得分:4)
如果我正确地理解了您教授的问题版本,他会尝试教您算法量级和确切执行时间之间的区别。
确切的执行时间需要大量的工作才能计算出来。
当你把它们全部加起来时,你会得到最好和最坏的情况方程:11n + 11是每个数组元素11个指令+11个开销; 12n + 11是每个数组元素12个指令+11个开销。
在算法的数量级上,代码是非常可预测的,因此它易于计算。因为每个输入数据没有中断或多次传递,所以每个数组元素需要一个循环O(n)。如果(比较)它将每个元素与每个其他元素进行比较,因此必须具有n个元素的内部循环和n个元素的外部循环,那将是O(n ^ 2)。简单的排序程序往往就是这样。
我认为本课程的核心是认识到计算执行的准确时间 HARD 。这个小例子没有考虑内存总线的速度,测试数据是否适合处理器的缓存,以及其他可能影响执行时间的其他事情。通过比较可以很容易地理解一般数量级(尽管在复杂算法上,它仍然很难)。通常订单就是您所需要的。在极少数情况下,您需要进行详细分析,现在您已了解如何进行...但粗略分析对于您需要做的几乎任何事情都是足够好的。
在职业发展的正常世界中,只有专家通常需要关心逐个教学的时间安排。了解算法的顺序可以让您在更高层次上比较您的想法,并在更合理的时间内得到正确的答案。
希望这有帮助!
答案 1 :(得分:1)
让我重新说一下:
因为我们都近似并且也忽略了实际的常数(例如 11 * t0),更容易推理如下。
在谈论复杂性时,我们并不关心常量。换句话说,具有11*n
指令的程序与具有12*n
指令的程序O(n)
具有相同的复杂性。
循环执行n次,循环内容不变 时间,所以总时间是O(n)。
循环执行n
次。在这种情况下,n=length
。在每次迭代中,我们评估a[i] > 5
,如果为真,我们会进行添加,如果为假,我们不会。换句话说,我们要么做一个指示,要么不做。换句话说,循环的主体需要O(1)
时间。如果您执行O(1)
任务n
次,则会导致O(n)
复杂度。
大多数时候我们只使用粗略的分析,这是合理的 通过详细分析。
粗略分析是O(1)*n = O(n)
。详细的分析是计算指示。
详细分析是指在最佳情况和最差情况下计算指令的时间。如果您获得相同的复杂性,在我们的案例中O(n)
,那么您已经证明您的粗略分析是正确的。
如果a[i] > 5
始终为false,则此程序将执行最少的指令。然后你得到11n + 11
个指令。
如果a[i] > 5
始终为真,则此程序将执行最多指令。然后你得到12n + 11
个指令。
当您删除常量时,两者都是n
,因此我们对O(n)
时间的估计是正确的。