在学习数据结构时,学习过算法的时间复杂度。时间复杂度主要用于比较算法的效率,从同一问题的多个算法中挑选出较优算法。
一、算法的时间复杂度
1.问题规模和语句频度
不考虑计算机的软硬件等环境因素,影响算法时间代价的最主要因素是问题规模。问题规模是算法求解问题输入量的多少,是问题大小的本质表示,一般用整数n表示。问题规模n对不同的问题含义不同,例如,在排序运算中n为参加排序的记录数,在矩阵运算中n为矩阵的阶数,在多项式运算中n为多项式的项数,在集合运算中n为集合中元素的个数,在树的有关运算中n为树的结点个数,在图的有关运算中n为图的顶点数或边数。显然,n越大算法的执行时间越长。
一个算法的执行时间大致上等于其所有语句执行时间的总和,而语句的执行时间则为该条语句的重复执行次数和执行一次所需时间的乘积。
一条语句的重复执行次数称作语句频度(Frequency Count)。由于语句的执行要由源程序经编译程序翻译成目标代码,目标代码经装配再执行,因此语句执行一次实际所需的具体时间是与机器的软、硬件环境(如机器速度、编译程序质量等)密切相关的。所以,所谓的算法分析并非精确统计算法实际执行所需时间,而是针对算法中语句的执行次数做出估计,从中得到算法执行时间的信息。
设每条语句执行一次所需的时间均是单位时间,则一个算法的执行时间可用该算法中所有语句频度之和来度量。
例1:求两个n阶矩阵的乘积算法
for(i=1; i<=n; i++) // 频度为 n + 1
for(j=1; j<=n; j++) // 频度为 n * (n + 1)
{
c[i][j] = 0; // 频度为 n^2
for(k=1; k<=n; k++) // 频度为 n^2 * (n + 1)
c[i][j] = c[i][j] + a[i][k] * b[k][j]; // 频度为 n^3
}
该算法中所有语句频度之和,是矩阵阶数n的函数,用f(n)表示之。换句话说,上例算法的执行时间与f(n)成正比。
理解:在for循环的语句中,存在n+1的情况,是因为在i=n时,循环还会继续,直到i=n+1,然后判断i<=n失败,才会退出循环,所以频度是n+1。
2.算法的时间复杂度定义
对于例1这种较简单的算法,可以直接计算出算法中所有语句的频度,但对于稍微复杂一些的算法,则通常是比较困难的,即便能够给出,也可能是个非常复杂的函数。因此,为了客观地反映一个算法的执行时间,可以只用算法中的“基本语句”的执行次数来度量算法的工作量。所谓“基本语句”指的是算法中重复执行次数和算法的执行时间成正比的语句,它对算法运行时间的贡献最大。通常,算法的执行时间是随问题规模增长而增长的,因此对算法的评价通常只需考虑其随问题规模增长的趋势。这种情况下,我们只需要考虑当问题规模充分大时,算法中基本语句的执行次数在渐近意义下的阶。如例1矩阵的乘积算法,当n趋向无穷大时,显然有
即当n充分大时,f(n)和n^3之比是一个不等于零的常数。即f(n)和n^3是同阶的,或者说 f(n)和n^3的数量级相同。在这里,我们用“O”来表示数量级,记作。由此我们可以给出下述算法时间复杂度的定义。
一般情况下,算法中基本语句重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作
它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称做算法的渐近时间复杂度,简称时间复杂度(Time Complexity )。
来源《数据结构(C语言版)》(第2版) 严蔚敏、 李冬梅、吴伟民