在搜索和排序算法中,我们需要考虑的不仅仅是正确性,个人认为算法的运行时间性能是另一个影响算法选择的重要因素。这里我们先介绍一些复杂性分析工具,以便评估算法的运行时间性能或效率。
一、评估算法的性能
在选择算法时,我们必须解决时间/空间的平衡问题。我们所设计的一个算法,可能获得了更快的运行速度,但却是以使用额外的空间(内存)或者其他的牺牲为代价。有些用户愿意付出更多的内存来换取一个更快的算法,但另一些则可能宁愿用一个较慢的算法也要节约内存。
目前,度量算法性能主要有这几种方法:
1.度量算法的运行时间
方法:首先确定几个具有相同大小的不同数据集合的时间(使用计算机的时钟来获取实际的运行时间),然后计算出平均的时间。接下来,针对越来越大的数据集合,收集相似的数据。在进行几次这样的测试后,就有了足够的数据能够预测算法对于任何大小的一个数据集合的表现了。
举例:比如一个算法,在处理第一个较小的数据集中,费时2s。在10倍于第一个数据集大小的数据集时,费时20s左右;100倍于第一个数据集大小的数据集,费时200s左右,则之后随着数据集的大小翻倍,则大致可以推测出需要花费的时间也应随之翻倍。
问题:(1)不同硬件平台的处理速度不同。程序的运行时间在不同类型的操作系统和硬件上也是不同的。不同的编程语言和编译器也会得到性能不同的代码。
(2)对于很大的数据集合来说,确定某些算法的运行时间是不切实际的。
2.统计指令
方法:统计对不同的问题规模所要执行的指令(根据问题规模,执行次数不同,这种指令一般在循环或递归函数中)的数目。
举例:斐波拉切数列
from counter import Counter """Count the number of calls of the Fibonacci function.""" def fib(n, counter): counter.increment() if n < 3: return 1 else: return fib(n-1,counter)+fib(n-2,counter) problemSize = 2 print("{:12d}{:15d}".format("Problem Size", "Calls")) for count in range(5): counter = Counter() fib(problemSize,counter) print("{:10d}{:12d}".format(problemSize,counter)) problemSize *= 2
注:书上这段代码无法输出结果,因为并没有counter这个包,我改为从collection这个包里,才如愿引用了Counter这个函数,估计是笔误的问题。还有counter.increment()这里,作者写的counter = Counter(),这里我查阅发现,意思为创建一个空的Counter类?而且Counter()函数中并不存在increment()这个方法。。。希望有懂得人可以解答一下。
最后输出的结果应为:
Problem Size Calls
2 1
4 5
8 41
16 1973
32 4356617
可以看到当数量为32时,得到的指令计数已经远远大于256(16x16)。
问题:对于某些算法来说,当问题规模非常大的时候,计算机还是无法运行得足够快。
3.度量算法所使用的内存
这个没啥好讲的,就是分析算法所需的内存数量及潜在的增长率。
4.复杂度分析
由图3.5可以看出,可能两种算法在数据量很小的时候,差别并不大。但随着问题规模的不断扩大,具有较高复杂度阶的算法的性能会更快地变得糟糕起来。
图3.6和表3.2是在算法分析中最常使用的复杂度阶。
表示方法:大O表示法 例:一个线性时间算法的阶是O(n)。
参考书:《数据结构(python语言描述)》