时间复杂度&空间复杂度《数据结构》清华大学出版社

时间复杂度&空间复杂度

时间复杂度

算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量。一般有两种方法:

  • 事后统计:利用计算机的计时功能。有明显的两种缺点,一、必须要运行起来才行。二、结果依赖于计算机硬件、软件环境,容易掩盖算法本身的优劣。所以该方法一半不可靠,多用后面一种方式。
  • 事前分析:一个程序在计算机上运行所消耗的时间取决于下列因素:
    1. 算法选用的策略。
    2. 问题规模。
    3. 书写程序的语言,实现语言级别越高,执行效率越低。
    4. 编译程序所产生的机器代码的质量。
    5. 机器执行指令的速度。

显然,同一个算法用不同的语言实现,或者用不同的编译程序进行编译,或者在不同的计算机上运行时,效率均不同。这表明使用绝对的时间单位衡量算法的效率是不合适的。撇开这些与计算机硬件、软件相关的因素,可以认为一个特定算法运行工作量的大小,只依赖于问题的规模(通常用整数n表示),或者说,它是问题规模的函数。

一个算法是由控制结构(顺序、分之和循环3中)和原操作(指固有数据类型的操作)构成的,则算法取决于两者的综合效果。为了便于比较同一问题的不同算法,从算法中选取一种对于所研究的问题来说是基本操作的原操作,以该基本操作重复执行的次数作为算法的时间度量。

例如,在如下所示的两个N×NN \times N 矩阵相乘的算法中,"乘法"运算是"矩阵相乘问题"的基本操作。整个算法的执行时间与该基本操作(乘法)重复执行的次数n3n^3 成正比,记作T(n)=O(n3)T(n) = O(n^3)

for (int i = 1; i <= n; ++i) {
  for (int j = 1; j <= n; ++j) {
    c[i][j] = 0;
  	for (int k = 1; k <= n; ++k) {
  		c[i][j] += a[i][k] * b[k][j]; // 基本操作(原操作)
		}
	}
}

一般情况下,算法中基本操作重复执行的次数是问题规模nn的某个函数f(n)f(n),算法的时间度计作
T(n)=O(f(n)) T(n) = O(f(n))
它表示随着问题规模nn的增大,算法执行时间的增长率和f(n)f(n)的增长率相同,被称作算法的渐进时间复杂度,简称时间复杂度

被称作问题的基本操作的原操作应该起重复执行次数和算法的执行时间成正比的原操作,多数情况下是深层循环语句中的原操作。它的执行次数和包含他的语句的频度相同。语句的频度是指该语句重复执行的次数,例如,在下列3个程序中:

(a) {++x; s = 0;}
(b) for (i = 1; i <= n; ++i) {++x; s+=x};
(c) for (j = 1; j <= n; ++j) 
  			for (k = 1; k <= n; ++k) {++x; s += x;}

含基本操作x+1x + 1的语句频度分别为1、n和n2n^2,则这三个程序段的时间复杂度分别为O(1)O(1)O(n)O(n)O(n2)O(n^2),分别称为常量阶、线性阶和平方阶。我们应该尽可能选用多项式阶O(nk)O(n^k)的算法,而不希望用指数阶的算法。

由于算法的时间复杂度考虑的只是对于问题规模nn的增长率,则在南艺精确计算基本操作执行次数的情况下,只需要求出它关于nn的增长率或者阶即可。

有的情况下,算法中基本操作重复执行的次数还随着问题的输入数据集不同而不同,因为各种输入数据集出现的概率难以确定,算法的时间复杂度也就难以确定。因此,可行的办法是讨论算法在最坏情况下的时间复杂度。一般而言,我们说的时间复杂度都是最坏情况下的时间复杂度。

空间复杂度

类似于算法的时间复杂度,空间复杂度是算法所需存储空间的度量,计作:
S(n)=O(f(n)) S(n) = O(f(n))
其中nn为问题的规模。一个执行的程序除了需要存储空间来寄存本身所用指令、常数、变量和输入数据外,也需要一些对数据进行操作的工作单元和存储一些为实现计算所需信息的辅助空间。如果输入数据所占空间指取决于问题本身,和算法无关,则只需要分析除输入和程序之外的额外空间,否则应同时考虑输入本身所需空间(和输入的表现形式无关)。若额外空间相对于输入数据量来说是常熟,则称此算法为原地工作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章