时间复杂度的理解和计算
时间复杂度的理解和计算
前言:重在记录,可能出错。
一、算法执行时间的表示
研究一个算法,我们先给出条件——忽略硬件的影响、忽略待处理数据的具体值,那么显而易得的,不同的单条语句执行时间相同,记为单位时间t。此时,算法执行时间T与所有语句执行次数\(f\)有关,而所有语句执行次数\(f\)又与待处理数据规模n有关,因此,T与n有关。
我们用函数\(f \left( n \right)\)、T(n)分别表示所有语句执行次数\(f\)和算法执行时间T和待处理数据规模n之间的关系。即:
\[\color{red}{T \left( n \left) =f \left( n \left) ∙t\right. \right. \right. \right. }
\]
二、时间复杂度的理解
1. 时间复杂度是用来大约表示算法执行时间随着待处理数据规模增大的增长趋势。
2. 我们在测算某个算法的时间效率时,无法做到将每个算法都运行一次。因此,我们通常采用“纸上谈兵”的方法,即在纸面上利用分析估算来研究一个算法的时间效率。
3. “纸上谈兵”要谈什么兵?对,比较不同算法的T(n)的大小,怎么比?对!比值!!在实际生活中,我们通常研究的是\({n \to \infty }\)时的值的大小,哦~,求极限。
\[{\mathop{{lim}}\limits_{{n \to \infty }}\frac{{T\mathop{{}}\nolimits_{{1}} \left( n \right) }}{{T\mathop{{}}\nolimits_{{2}} \left( n \right) }}=\mathop{{lim}}\limits_{{n \to \infty }}\frac{{f\mathop{{}}\nolimits_{{1}} \left( n \left) t\right. \right. }}{{f\mathop{{}}\nolimits_{{2}} \left( n \left) t\right. \right. }}=\mathop{{lim}}\limits_{{n \to \infty }}\frac{{f\mathop{{}}\nolimits_{{1}} \left( n \right) }}{{f\mathop{{}}\nolimits_{{2}} \left( n \right) }}\text{ }?\text{ }1}
\]
分析这个式子,我们发现在n趋近于∞的过程中,当\({T\mathop{{}}\nolimits_{{1}} \left( n \right) }\)的增长快于\({T\mathop{{}}\nolimits_{{2}} \left( n \right) }\)时,必然存在一个\({n\mathop{{}}\nolimits_{{0}} \in R\mathop{{}}\nolimits^{{+}}}\),满足\({n > n\mathop{{}}\nolimits_{{0}}},{T\mathop{{}}\nolimits_{{1}} \left( n \left) > T\mathop{{}}\nolimits_{{2}} \left( n \right) \right. \right. }\)。对于单调递增函数,反过来依然成立,也就是说:\({\mathop{{lim}}\limits_{{n \to \infty }}T \left( n \right) }\)越大,$T \left( n \right) $增长越快。
我们用时间复杂度来表示函数的增长趋势,用大O符号来表示函数无穷大渐近的值(在这里可以理解为一个单调递增函数的最大值),则O越大,时间复杂度越大。常见增长趋势大小的有O(常数)<O(对数函数)<O(幂函数)<O(指数函数)。具体的有:
为了便于分析,我们直接说时间复杂度等于$\color{red}{O\left(f\left(n \left) \right) \right. \right. } $,也就是用O来表示增长趋势。
三、时间复杂度的计算
\({O\left(f\left(n \left) \right) \right. \right. }\)来表示增长趋势,显而易得的,有以下结论:
1. 趋势乘以一个常数k,趋势不变。
2. 待处理数据的规模n不影响趋势的大小
3. 大趋势加上一个小趋势仍等于自身大趋势不变。
用公式表示以上两个结论,我们就可以得到时间复杂度的计算公式:
1. \(\color{red}{O \left( kf \left( n \left) \left) =O \left( f \left( n \left) \right) \right. \right. \right. \right. \right. \right. }\)
2. \(\color{red}{O \left( f \left( a \left) \left) =O \left( f \left( b \left) \right) \right. \right. \right. \right. \right. \right. }\)
3. \(\color{red}{O \left( f \left( n \left) +g \left( n \left) \left) =O \left( max \left\{ O \left( f \left( n \left) \left) ,{\left. O \right( }g \left( n \left) \left) \left\} \right) \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. \right. }\)
例:有以下程序片段,求时间复杂度:
1.
void fun(int n){
int a;//执行1次
for(int i=0;i<6;i++){//i=0执行1次,i<6执行7次,i++执行6次
a=i;//执行6次
}
}
所有语句执行次数\(f\)(n)=1+1+7+6+6=21,时间复杂度为:
O(\(f\)(n))=O(21)=O(21*1)=O(1)=O(6*1)=O(6)
2.
void fun(int n){
int a;//执行1次
for(int i=0;i<n;i++){//i=0执行1次,i<n执行n+1次,i++执行n次
a=i;//执行n次
}
}
所有语句执行次数\(f\)(n)=1+1+(n+1)+n+n=3n+3,时间复杂度为:
O(\(f\)(n))=O(3n+3)=O(max{O(3n),O(3)})=O(3n)=O(n)
3.
void fun(int n){
int a;//执行1次
for(int i=0;i<n;i++){//i=0执行1次,i<n执行n+1次,i++执行n次
for(int j=0;j<n;j++){//j=0执行n次,j<n执行n²+n次,i++执行n²次
a=j;//执行n²次
}
}
}
所有语句执行次数\(f\)(n)=1+1+(n+1)+n+n+(n²+n)+n²+n²=3n²+4n+3,时间复杂度为:
O(\(f\)(n))=O(3n²+4n+3)=O(max{O(3n²),O(4n),O(3)})=O(3n²)=O(n²)
综上,可以看出求时间复杂度时只需要求执行次数最多的语句的执行次数,一个含n的项式,并且将系数定为1即可,执行次数最多的语句一般就是最深层的语句(最基本语句)。
4.
void fun(int n){
int a;
for(int i=1;i<n;i*=2){
a=i;
//设此语句执行x次,则2ˣ=n-Δ(n),0≤Δ(n)≤n-1,代表误差
//两边同时取以2为底的对数得:
//log₂2ˣ=log₂(n-Δ(n)),0≤Δ(n)≤n-1,代表误差,代表误差
//xlog₂2=log₂(n-Δ(n)),0≤Δ(n)≤n-1,代表误差
//x=log₂(n-Δ(n)),0≤Δ(n)≤n-1,代表误差
}
}
}