Algorithm “基本”的大O分析中的不一致性;算法";
我最近学习了算法的形式化Big-O分析;然而,我不明白为什么这两种算法的运行时间会有很大的不同,这两种算法实际上做的是相同的事情。这两种算法都打印0到n的数字。我将用伪代码编写它们:Algorithm “基本”的大O分析中的不一致性;算法";,algorithm,big-o,analytics,Algorithm,Big O,Analytics,我最近学习了算法的形式化Big-O分析;然而,我不明白为什么这两种算法的运行时间会有很大的不同,这两种算法实际上做的是相同的事情。这两种算法都打印0到n的数字。我将用伪代码编写它们: Algorithm 1: def countUp(int n){ for(int i = 0; i <= n; i++){ print(n); } } Algorithm 2: def countUp2(int n){ for(int i = 0; i
Algorithm 1:
def countUp(int n){
for(int i = 0; i <= n; i++){
print(n);
}
}
Algorithm 2:
def countUp2(int n){
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
... (continued so that this can print out all values 0 - Integer.MAX_VALUE)
for(int z = 0; z < 10; z++){
print("" + i + j + ... + k);
if(("" + i + j + k).stringToInt() == n){
quit();
}
}
}
}
}
算法1:
def倒计时(整数n){
对于countUp
中的(int i=0;i),循环一次命中[0,n]范围内的所有数字,从而导致运行时间为O(n)
在countUp2
中,您做了一些完全相同的事情,多次。所有循环的边界都是10
假设有3个循环以10为界运行。因此,外部循环是10
,内部循环是10x10
,最内部循环是10x10x10
。因此,最坏情况下,最内部循环将运行1000次,这基本上是恒定时间。因此,对于n
有界的循环[0,10],您的运行时为10^n,这也可以称为常数时间O(1),因为它不依赖于最坏情况分析的n
假设您可以编写足够多的循环,并且n
的大小不是一个因素,那么您需要为n的每一个数字创建一个循环。n
中的位数是int(math.floor(math.log10(n))+1
;我们称之为dig
。因此,迭代次数的更严格上限为10^dig(可以简化为O(n);证明留给读者作为练习)。在分析算法的运行时时,需要寻找的一个关键因素是循环。在算法1中,代码执行n次,使运行时为O(n)。在算法2中,嵌套循环每次运行10次,因此运行时为O(10^3)。这是因为您的代码对中间循环的每次运行都会运行最内层循环10次,而中间循环对最外层循环的每次运行都会运行10次。因此,代码会运行10x10次。(但这纯粹是一个上限,因为您的if语句可能会在循环完成之前结束算法,具体取决于n的值).若要在countUp2
中最多计算n
,则需要与n
中的位数相同的循环数:所以log(n)
循环。每个循环可以运行10次,因此总迭代次数为10^log(n)
,即O(n)
第一次在O(n log n)中运行时间,因为打印(n)
输出O(对数n)位
第二个程序假设n的上限,所以O(1)很小。当我们进行复杂度分析时,我们假设编程语言的一个更抽象的版本,其中(通常)整数是无界的,但算术运算仍然在O(1)中执行。在您的示例中,您混淆了实际的编程语言(有界整数)对于这个更抽象的模型(它没有)。如果你重写程序[*],使它有一个根据n动态调整的循环数(因此,如果你的数字n有k位,则有k+1个嵌套循环),那么它会对每个数字进行一次最内层代码的迭代,从0到n后的下一个10次方(logn)在构造字符串时工作[**],因此整个程序也是O(nlogn)
[*]您不能使用for循环和变量来实现这一点;您必须使用递归或类似的方法,使用数组而不是变量i,j,k,…,z
[**]这是假设您的编程语言优化了k长度-1字符串的添加,使其在O(k)时间内运行。明显的字符串连接实现是O(k^2)时间,这意味着您的第二个程序将在O(n(logn)^2)时间内运行。第二个函数可能比第一个函数慢,但它仍应在O(n)时间内运行时间。你是如何得到O(n^10)的?@AtnNn第二个O(n)是怎样的?所有循环都是以10为界的如果你把数字11放入第二个算法中,你会得到输出,“0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,8,2,3,4,5,6,7,8,9,10,11”这与第一个不同。@DebosmitRay循环也以条件为界(“”+i+j+k).stringToInt()==n
@AtnNn如果我错了,请纠正我。但这不应该影响最坏情况下的运行时间,对吗?如果n
是循环可以达到的最大值的一倍呢?对于m
循环,循环在10^m
处最大,这是一个常量。你的意思是什么?哪里使用n
作为循环边界?循环边界独立于n@DebosmitRay为了与第一个示例保持一致,我使用了n来解释循环是如何影响分析的。我想我应该使用另一个字母,因为在本例中n用于单独的目的。循环边界是常量。因此使用n
会引起不必要的混淆。@DebosmitRay Good点。希望编辑后更清楚。是的,先生,我想是。:)好的。我明白了。因为for循环是由一个常数限定的,所以它意味着它只是在O(n)中运行time@dsiegler19不,长官,Big-O分析表明,在最坏的情况下,第二个函数在O(1)中运行。