我找到了一些关于大O表示法的参考文献,但据我所知,算法复杂度是输入数据大小的函数。
例如,如果冒泡排序的复杂性为O(n^2)
,则n
是输入数组的大小。正确?
但是,我如何确定具有固定输入大小并取决于输入值的算法的复杂性。例如,找到最大公约数(GCD)将如下所示:
def GCD(x, y):
while x != y:
if x < y:
x, y = y - x, x
else:
x, y = x - y, x
return x
这个算法的复杂性是什么?它是如何确定的?
编辑:更改了函数的名称和更正的算法名称。 ShreevatsaR,谢谢你指出来。
答案 0 :(得分:11)
人们用大O符号快速松散地玩耍。就GCD而言,他们通常以两种方式进行:
1)你是对的,算法复杂度,因此大O符号,应该根据输入的位大小来表示,而不是根据输入的值来表示。这就是P,NP等的定义方式。假设二进制输入和任意大数(如BigNum表示)和N输入的位数,您的GCD最多需要2 ^ N个减法,每个减法需要时间O(N)来运行每个数字。数字被减去。所以它是O(N * 2 ^ N)。如果使用除法而不是减法,GCD当然可以更快地完成:O(N ^ 2)。
所以,当我们说testing primality was proved in 2002 to be done in polynomial time时,这就是复杂性的技术定义,我们的意思是多项式的位数(这是棘手的部分),而不是输入数字本身的多项式(这是简单的使用试验分区在“亚线性时间”很容易做到。)
但实际上,对于采用固定数量的整数输入的算法,讨论复杂性更方便,好像N是输入本身,而不是输入的大小。只要你清楚自己在可能含糊不清的情况下的意思,它就没有害处。
2)实际上,整数输入通常是固定大小,32位或其他,并且对它们的操作(例如加法,乘法和除法)是O(1)时间。我们在订单分析中有选择地使用这些事实。从技术上讲,如果你的GCD程序只接受最多(2 ^ 32-1)的输入,那么它是O(1)。它的运行时间有一个固定的上限。分析结束。
虽然技术上正确,但这不是一个非常有用的分析。你在真正的计算机上做的几乎任何东西都是O(1)在相同的基础上,问题的大小受到硬件的限制。
接受添加为O(1)通常更方便,因为数字是固定大小的,但忽略GCD也是O(1),假设它在[1,2 ^ 32]范围内的行为延伸无限,并在此基础上进行分析。然后用N作为两个输入的最大值,得出O(N):O(N)减法,每个减法都是恒定时间。
再次,一旦你知道参考条款是什么,这一点并不含糊,但要注意错误地将我给出的Euclid算法的第一次分析与除法O(N ^ 2)进行比较,并将此算法与减法算法进行分析, 上)。 N在每个中都不相同,减法不更快; - )
答案 1 :(得分:2)
Big-O表示法应指定测量内容。
例如,排序算法的Big-O表示法通常用于衡量比较次数。
可以衡量您的GCD示例,将x
和y
的值与执行的指令数进行比较。让我们仔细看看:
def GCD(x, y):
while x != y: # 1
if x < y: # 2
x, y = y - x, x # 3
else: # 4
x, y = x - y, x # 5
return x # 6
从内到外工作。
无论x
和y
的值如何,步骤3和5始终会接受一条指令。因此,第2步的if
语句将始终采用两条指令。
更难的问题是第1步。每次迭代时,x
或y
都会被较小的值降低。假设x > y
。将发生以下两件事之一:
如果它开始x % y == 0
,则循环将执行(x / y) - 1
次,程序将停止。
否则x
会在(x / y)
小于y
之前减少x
次,程序将会继续。
您可以轻松衡量任何给定y
和z
的指令数量。您可以轻松地显示,对于给定的数字z - 1
,您永远不会需要超过2 * (z-1)
次删除或gcd(z, 1)
指令。 (想想{{1}}。)
答案 2 :(得分:1)
输入大小是数字x
和y
的大小之和(例如,数字中有多少位数)
答案 3 :(得分:1)
Big O复杂性是最坏的情况渐近运行时行为。它不一定取决于特定算法的输入大小(输入数量) - 尽管通常情况就是如此。换句话说,它是描述运行时的限制函数,因为输入被带到无穷大。
在您的情况下,如果x或y是无界的,渐近运行时也是如此。如果没有,请考虑运行时间,如果x = 1,y = Int32.Max?