大多数拥有计算机科学学位的人肯定知道大O代表什么。 它帮助我们衡量一个算法的可扩展性。

但我很好奇,你是如何计算或近似你的算法的复杂性的?


当前回答

我想从另一个角度来解释Big-O。

Big-O只是用来比较程序的复杂性,也就是当输入增加时它们的增长速度有多快,而不是花在执行操作上的确切时间。

恕我直言,在大o公式中,你最好不要使用更复杂的方程(你可以坚持使用下图中的方程)。然而,你仍然可以使用其他更精确的公式(如3^n, n^3,…),但有时会误导!所以还是尽量简单为好。

我想再次强调,这里我们不想得到一个精确的算法公式。我们只想展示当输入增加时它是如何增长的并在这方面与其他算法进行比较。否则,您最好使用不同的方法,如基准测试。

其他回答

看到这里的答案,我想我们可以得出这样的结论:我们大多数人确实通过观察它和使用常识来近似算法的顺序,而不是像我们在大学里认为的那样用主方法来计算它。 说了这么多,我必须补充一点,即使教授也鼓励我们(后来)实际思考,而不是仅仅计算。

我还想补充一下如何对递归函数进行处理:

假设我们有这样一个函数(scheme code):

(define (fac n)
    (if (= n 0)
        1
            (* n (fac (- n 1)))))

递归地计算给定数字的阶乘。

第一步是尝试并确定函数体的性能特征,只是在这种情况下,在函数体中没有做任何特殊的事情,只是一个乘法(或返回值1)。

所以主体的性能是:O(1)(常数)。

接下来尝试确定递归调用的数量。在这种情况下,我们有n-1个递归调用。

所以递归调用的性能是:O(n-1)(阶为n,因为我们抛弃了无关紧要的部分)。

然后把这两个放在一起,你就得到了整个递归函数的性能:

1 * (n-1) = O(n)


Peter, to answer your raised issues; the method I describe here actually handles this quite well. But keep in mind that this is still an approximation and not a full mathematically correct answer. The method described here is also one of the methods we were taught at university, and if I remember correctly was used for far more advanced algorithms than the factorial I used in this example. Of course it all depends on how well you can estimate the running time of the body of the function and the number of recursive calls, but that is just as true for the other methods.

将算法分解成你知道的大O符号,并通过大O运算符组合。这是我知道的唯一办法。

欲了解更多信息,请查看有关该主题的维基百科页面。

我不知道如何通过编程来解决这个问题,但人们做的第一件事是我们对算法的特定模式进行抽样,比如4n²+ 2n + 1我们有两个规则:

如果我们有一个项的和,增长率最大的项被保留,其他项被省略。 如果我们有几个因数的乘积,常数因数就省略了。

如果我们化简f(x),其中f(x)是所做操作数量的公式,(上文解释的4n²+ 2n + 1),我们得到大O值[在这种情况下是O(n²)]。但这必须考虑到程序中的拉格朗日插值,这可能很难实现。如果真正的大O值是O(2^n)我们可能有O(x^n)这样的东西,那么这个算法可能是不可编程的。但如果有人证明我错了,给我代码. . . .

虽然知道如何计算出特定问题的大O时间是有用的,但了解一些一般情况可以在很大程度上帮助您在算法中做出决策。

以下是一些最常见的案例,摘自http://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions:

O(1) -确定一个数字是偶数还是奇数;使用常量大小的查找表或哈希表

O(logn) -用二分搜索在排序数组中查找一个项

O(n) -在未排序的列表中查找一个项;两个n位数相加

O(n2) -用一个简单的算法乘以两个n位数字;添加两个n×n矩阵;冒泡排序或插入排序

O(n3) -用简单的算法乘以两个n×n矩阵

O(cn) -使用动态规划找到旅行商问题的(精确)解;使用蛮力判断两个逻辑语句是否等效

O(n!) -通过暴力搜索解决旅行推销员问题

O(nn) -通常用来代替O(n!)来推导更简单的渐近复杂度公式

基本上90%的情况下都是分析循环。你有单、双、三重嵌套循环吗?你有O(n) O(n²)O(n³)的运行时间。

很少(除非你正在编写一个具有广泛基库的平台(例如,.NET BCL或c++的STL),你会遇到比查看循环(for语句,while, goto等…)更困难的事情。