我试图从教授的讲义中理解复杂性类算法,但我仍然无法掌握它。
void sort(int a[], int N) { //N is the length of the array
for (int base=0; base<N; ++base)
for (int check=base+1; check<N; ++check)
if (a[base] > a[check])
std::swap(a[base], a[check]);
}
在他的笔记上,他说这个表达是8N ^ 2 + 12N + 6。
据我完全理解,这个复杂性类别是N ^ 2,因为它是其余的增长最快的。我们忽略常数,因为它们在进入无穷大时无关紧要。
但是,我想知道 他是如何获得常量的。
我不明白他是如何获得+ 6.当这个函数被调用一次时,究竟只运行了6次?我看到 int base = 0 只创建一次,因为它属于外部for循环。
编辑:所以我发现+ 6只是这个函数需要运行的最小值。如果for循环只执行一次...所以总行数?好吧,我们复制一个[]和int N,然后我们有for-loops和if语句。总而言之,一切都增加到了6个。
12N怎么样?
答案 0 :(得分:3)
正如 Ami Tavory 所说,这看起来像废话。经过仔细观察之后,它仍然是非常奇怪的,因为表达式混合了非常不同的操作循环,因为它将是原子的...如果我忽略了相关性,我会这样看:
void sort(int a[], int N) { // ?T
for (int base=0; base<N; ++base) // 1 +(3+2)N
for (int check=base+1; check<N; ++check) // 2N+(3+2)M
if (a[base] > a[check]) // (2+1+2)M
std::swap(a[base], a[check]); // (2+2+2)M
}
我做了狂野假设关于内存/寄存器/直接访问或ALU操作的周期数。 M = ~ (N^2)/2
(抱歉懒得从系列总和得到实际计数)是内循环迭代的数量。所以,当我总结时,我得到了:
16*(N^2)/2+7N+1+?
8*N^2 + 7N + 1+?
这与你的表达非常接近。由于我使用了不准确的M
并且不知道这背后的架构,结果可能会改变一点,可能有利于你的表达。因此函数init和return考虑~5
个周期。如果我变得更加狂野那么:
int a[]; // 2 // heap -> reg
int N; // 2 // heap -> reg
{} // 1 // stack return (I would guess it should be also 2)
所以我得到了:
8*N^2 + 7N + 6
反对你的:
8*N^2 + 12N + 6
要使此准确,您应该:
M
将代码分解为原子操作
区分直接/内存(堆/堆栈)/注册访问(可能甚至读/写), ALU 操作等等。 ..例如swap(a,b) { c=a; a=b; b=c; }
如果它不是由 Xor 完成的......现在你可以像我试过的那样计算周期......
例如,查看Machine cycle timings for Z80这里是我的Zilog Z80A完整指令集的链接,其中包含机器周期时序。因此,您可以看到每种类型的指令实际上有多么不同。对于正在学习这些内容的平台/架构,你应该有类似的东西。