【数据结构】算法的渐进分析-渐进时间复杂度

 算法的渐进分析(asymptotic algorithm analysis)简称算法分析。算法分析直接与它所求解的问题的规模 n 有关,因此,通常将问题规模作为分析的参数,求算法的时间和空间开销与问题规模的关系。

渐进的时间复杂度

 计算程序步数的目的是想比较两个或多个完成相同功能的程序的时间复杂度,并估计当问题规模变化时,程序的运行时间如何随之变化。
 要确定一个程序的准确的程序步数是非常困难的,而且也不是很必要。因为程序步数这个概念本身不是一个精确的概念。例如,赋值语句 x=a 和 x=a+b*(c-d)-e/f 居然具有相同的程序步数。
 由于程序步数不能确切的反映运行时间,所以用精确的程序步数来比较两个程序,其结果不一定有价值。前面讨论迭代求和程序与递归求和程序的程序步数时,程序步数为 3n+2 的程序反而比程序步数为 3n+4 的程序运行时间多。但是,当两个程序的程序步数相差很大时,例如一个是 ⌈ log ⁡ 2 ( n + 1 ) ⌉ \lceil\log_2(n+1)\rceil log2(n+1),另一个是 n ∗ ( n − 1 ) / 2 n*(n-1)/2 n(n1)/2 时,明显后者比前者运行时间多。
 因此,如果精确计算有困难,我们只要能够得出一个是 log ⁡ 2 n \log_2n log2n的数量级,一个是 n 2 n^2 n2的数量级,后者比前者运行时间多的结论,也能达到分析的目的。

O O O 渐进表示

  要全面分析一个算法,需要考虑算法在最坏情况下的时间代价,在最后情况下的时间代价,在平均情况下的时间代价。对于最坏情况,主要采用大 O O O 表示法来描述。
  大 O O O 表示法的一般前提是:当且仅当存在正整数 c c c n 0 n_0 n0,使得 T ( n ) ≤ c f ( n ) T(n)\leq cf(n) T(n)cf(n),使得所有的 n ≥ n 0 n\geq n_0 nn0 成立,则称该算法的时间增长率在 O ( f ( n ) ) O(f(n)) O(f(n)) 中,记为 T ( n ) = O ( f ( n ) ) T(n)=O(f(n)) T(n)=O(f(n))
  使用大 O O O 表示法时需要考虑关键操作的程序步数。如果最后需要给出的时渐进值,可直接考虑关键操作的程序步数,找出其与 n n n 的函数关系 f ( n ) f(n) f(n) ,从而得到渐进时间复杂度。

接下来,根据大 O O O 表示法来看看接下来的例子。
1、(线性函数)考察 T ( n ) = 3 n + 2 T(n)=3n+2 T(n)=3n+2
T ( n ) = O ( n ) T(n)=O(n) T(n)=O(n)
2、(平方函数)考察 T ( n ) = 10 n 2 + 4 n + 2 T(n)=10n^2+4n+2 T(n)=10n2+4n+2
T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2)
3、(指数函数)考察 T ( n ) = 6 ∗ 2 n + n 2 T(n)=6*2^n+n^2 T(n)=62n+n2
T ( n ) = O ( 2 n ) T(n)=O(2^n) T(n)=O(2n)
4、(常数函数)考察 T ( n ) = 9 T(n)=9 T(n)=9
T ( n ) = O ( 1 ) T(n)=O(1) T(n)=O(1)

为了更好在具体情况下使用大 O O O 表示法,我们需要知道大 O O O 表示法的几个规则。

1、加法规则: 当两个并列的的程序段的时间代价分别为为 T 1 ( n ) = O ( f ( n ) ) T_1(n)=O(f(n)) T1(n)=O(f(n)) T 2 ( m ) = O ( g ( m ) ) T_2(m)=O(g(m)) T2(m)=O(g(m)) 时,那么将两个程序段连在一起后整个程序段的时间代价为
T ( n , m ) = T 1 ( n ) + T 2 ( m ) = O ( max ⁡ { f ( n ) , g ( m ) } ) T(n,m)=T_1(n)+T_2(m)=O(\max \{f(n),g(m)\} ) T(n,m)=T1(n)+T2(m)=O(max{f(n),g(m)})
所谓 max ⁡ { f ( n ) , g ( m ) } \max\{f(n),g(m)\} max{f(n),g(m)} 是指当 n n n m m m 充分大时取 f ( n ) f(n) f(n) g ( m ) g(m) g(m) 中的最大值。在这个意义下显然有如下关系:
c < log ⁡ 2 n < n < n log ⁡ 2 n < n 2 < n 3 < 2 n < 3 n < n ! c<\log_2n<n<n\log_2n<n^2<n^3<2^n<3^n<n! c<log2n<n<nlog2n<n2<n3<2n<3n<n!

示例如下

//程序 1.26	计算渐进时间复杂度的程序示例
void example(float x[][n],int m){
	float sum[m];
	int i,j;
	for(i=0;i<m;i++){
		sum[i]=0.0;
		for(j=0;j<n;j++)
			sum[i]+=x[i][j];			//计算第 i 行的元素和
		}
	for(i=0;i<m;i++)
		cout<<"Line"<<i<<":"<<sum[i]<<endl;			//打印第 i 行的累加和
}

根据加法规则,该程序的渐进时间复杂度为 O ( max ⁡ { m × n , m } ) O(\max\{m\times n,m\}) O(max{m×n,m})

2、乘法规则: 如果存在多层的嵌套循环,关键操作应在最内层循环中。先自外向内层层分析每层循环的渐进时间复杂度,然后利用大 O O O 表示法来计算其渐进时间复杂度。也就是说,当两个嵌套的程序段的时间代价分别是 T 1 ( n ) = O ( f ( n ) ) T_1(n)=O(f(n)) T1(n)=O(f(n)) T 2 ( m ) = O ( g ( m ) ) T_2(m)=O(g(m)) T2(m)=O(g(m)) 时,那么整个时间段的时间代价为
T ( n , m ) = T 1 ( n ) × T 2 ( m ) = O ( f ( n ) × g ( m ) ) T(n,m)=T_1(n)\times T_2(m)=O(f(n)\times g(m)) T(n,m)=T1(n)×T2(m)=O(f(n)×g(m))

你可能感兴趣的:(数据结构)