通常我们评判算法优劣时总少不了对算法在时间开销方面进行评估。
其中比较常用的是大O阶记法。
首先,我们明晰一个前提,决定算法在时间方面开销的因素可以简化为两个:
问题规模 和 算法的好坏。
所以很自热地我们可以通过算法的时间开销和问题规模来讨论算法的好坏。而其中算法时间方面的开销我们又可以近似地对应算法基本运算的执行次数。
在这个前提下分析:
算法基本运算的执行次数可以视作一个函数,姑且认为它的值和问题规模n有关,记为T(n).
①当问题规模的变化不会明显地影响算法基本运算方面地开销,即T(n)实际上是一个常数,我们就认为这种算法的时间复杂度可以记为O(1)。
②当算法基本运算的执行次数会随着问题规模变化,也就是说T(n)是一个含有n的关系式。在此基础上分析:
首先我们对算法的期望总是很高很高的,要对他委以重任。落在复杂度分析方面我们会需要假设n足够大。
因为n已经足够大,所以常数部分就变得无关紧要了,略去。
因为n已经足够大,所以非最高次项的值也变得无关紧要了,略去
还是因为n已经足够大,所以n前面的系数又变得无关紧要了,再略去。
最后我们就得到了一个相对简单的n的阶,这就是O记为的值了。
下面给出一个例子。
//time complexity example
for ( int i = 0 ; i < 10 ; i++){
printf_s ( "%d", i); //执行10次
}//end for
for ( int i = 0 ; i < n ; i++){
printf_s ( "%d", i);
for ( int j = i ; j < n ; j++){
printf_s ( "%d", j); //执行(n^2)/2 + n/2次
}
}
简单数一数,不考虑for循环语句自身的调用,算法一共执行了printf这个基本运算10 + (n^2)/2 + n/2 次。
常数部分略去,(n^2)/2 + n/2
非最高次项略去,(n^2)/2
系数略去,n^2
得到该算法的时间复杂度为O(n^2)。
附常见的时间复杂度
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)