14天阅读挑战赛
上一节说到算法的基本概念,算法与数据结构的关系,那算法的好坏是怎么度量的呢?这一节我们就来探讨一下。
所谓一个好的算法,无非是执行效率高,所用时间短,当然这时间的快慢有时和计算机有一定的关系,计算机内存的大小,处理器的处理速度都影响着计算结果输出的时间,我们研究算法,必须抛开这些外界因素,把代码块孤立出来,单纯来看、来研究代码块运行的时间,同样,代码块也要抛开各种编程语言编译机制的不同,单纯用所见到的代码来看所使用算法的执行效率。
算法的度量方法分为事后的统计方法和事前分析评估方法。
事后的统计方法:是通过对编制好的程序和数据,用不同的算法进行运行,比较得出最优算法的方法。
这种方法有几个很大的缺陷:一是需要设计完相关的程序,如果设计的算法不合理,设计出的程序将是没有意义的。二是处理器的处理速度,有时会掩盖算法的不足。三是对测试数据的设计必须全面,有时很难找到真正能够测试出性能优劣的临界数值。例如,一个数据是数量级,我们找到的n的测试数量级是10,得出的数值是1024,如果n取11才是真正的测试临界数值,得出的数值是2048,这是整整一倍的增量,所以说,测试的数值不容易找到合适的。
事前分析评估方法:在程序编制前,依据统计法对算法进行估算。
算法的估算取决于以下几个因素:
1、算法采用的方法;
2、编译代码质量;
3、数据的输入规模;
4、机器执行指令的速度。
我们可以看到,算法估算的因素中,与我们直接有关的只有1和3两个因素,而这两个因素对算法的运行又有什么影响呢,我们通过下表看一看。
问题规模 | 算法1(n+5) | 算法2(n) | 算法3(2n+2) | 算法4(2n) |
n=1 | 6 | 1 | 4 | 2 |
n=2 | 7 | 2 | 6 | 4 |
n=3 | 8 | 3 | 8 | 6 |
n=10 | 15 | 10 | 22 | 20 |
n=50 | 55 | 50 | 102 | 100 |
n=100 | 105 | 100 | 202 | 200 |
通过分析我们能够发现,当n=1,n=2时,算法1和算法3进行对比,算法1不如算法3,当n=3时,两者就一样了,但从n>3开始,算法3明显开始极大的高于算法1,因此,我们可以从整体上说,算法1的设计好于算法3的设计。同样我们也能够发现,当n=1,n=2,n=3时候,算法1比算法2、算法3比算法4要高很多,但当随着数据的增大,两者的数量级差距明显变小,当n=100时,就显得那么微不足道了,这显然,普通的常数对算法的影响可以忽略不计,在以后的计算中,我们便可以把这些常量舍去,能够更好的化简相关的数据,去掉干扰因素,对算法的好坏有更好的分析。
说到这里,不得不引出一个定义:函数的渐进增长。
函数的渐进增长是指,给定两个函数F(n)和G(n),如果存在一个正整数N,使得当所有的n>N时,F(n)总是大于G(n)的值,那么,我们就说F(n)增长渐进快于G(n)。
这渐进增长又和哪些因素有关呢?刚才说到,和后面的常数没有关系,我们继续研究一下子,看下面的表格。
问题规模 | 算法5(2+2n+1) | 算法6() | 算法7(2+2n+1) | 算法8() |
n=1 | 5 | 1 | 5 | 1 |
n=2 | 13 | 4 | 21 | 8 |
n=3 | 25 | 9 | 61 | 27 |
n=10 | 221 | 100 | 2021 | 1000 |
n=50 | 5101 | 2500 | 250101 | 125000 |
n=100 | 20201 | 10000 | 2000201 | 1000000 |
通过算法5和算法7来对比,当n=1时,两个算法相同,当n=2时,算法7略高于算法5,但随着n的增大,我们会发现,最高次项的指数数值,随着n的增大,决定了结果的增长快慢,指数越大,增长越快。
那还有没有别的因素相关呢,我们再来看下一个表格。
问题规模 | 算法9(8n+6) | 算法10(n) | 算法11(2+2) | 算法12() |
n=1 | 14 | 1 | 4 | 1 |
n=2 | 22 | 2 | 10 | 4 |
n=3 | 30 | 3 | 20 | 9 |
n=10 | 86 | 10 | 202 | 100 |
n=50 | 406 | 50 | 5002 | 2500 |
n=100 | 806 | 100 | 20002 | 10000 |
我们来对比算法9和算法11,当n=1,n=2,n=3时候,算法9要大于算法11,但当n不断增大,算法11的增长速度明显加快,远远地大于算法9,因此,我们看到,数据的增长的更多的在于最高次项是多少,而最高次项前面的系数,每个式子中最高次项前面的常数就显得不重要了。
上面提到,算法的评估与加上的常数项无关,与最高次项的常数无关,与最高次项的指数数值有关,那还有其他的关联因素吗?我们接着来看下面的表格。
问题规模 | 算法13(3n+1) | 算法14(3) | 算法15(3+3n+1) |
n=1 | 4 | 3 | 7 |
n=2 | 7 | 12 | 19 |
n=3 | 10 | 27 | 37 |
n=10 | 31 | 300 | 331 |
n=50 | 151 | 7500 | 7651 |
n=100 | 301 | 30 000 | 30 301 |
n=1000 | 3 001 | 3 000 000 | 3 003 001 |
n=10 000 | 30 001 | 300 000 000 | 300 030 001 |
n=100 000 | 300 001 | 30 000 000 000 | 30 000 300 001 |
通过表格我们可以发现,随着n的增大,3n在3+3n+1中对数值增加起到的作用越来越小,3+3n+1与 3的数值也越来越近,因此,我们可以得出结论,我们关注最高项阶数就可以了,把常数和其他次要项可以忽略。
因此,随着n的增加,我们会发现,它会越来越接近某一个最优的算法,也会越来越远离一个最差的算法,而这个最优的算法就是我们学习本门课程所期待找出来的。
下一节,我们将学习怎么样量化算法的复杂度,算法的时间复杂度和空间复杂度。