时间复杂度:
算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于0,则称f(n)是T(n)的同数量级函数,记为T(n)=O(f(n)),称O(f(n))为渐进时间复杂度,简称时间复杂度。
分析:随着模块n的增大,算法执行的时间的增长率和 f(n) 的增长率成正比,所以 f(n) 越小,算法的时间复杂度越低,算法的效率越高
计算方法:
在计算时间复杂度的时候,先找出算法的基本操作,然后根据相应的各语句确定它的执行次数,再找出 T(n) 的同数量级(它的同数量级有以下:1,log2n,n,n log2n ,n的平方,n的三次方,2的n次方,n!),找出后,f(n) = 该数量级,若 T(n)/f(n) 求极限可得到一常数c,则时间复杂度T(n) = O(f(n))
简单来说,时间复杂度就是基本语句的执行次数,计算时记住两点原则:
1.只看高阶项
2.不要系数
比如:
(1)
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
++x;a[i,j]=x; //3
}
}
计算的时候,不必计算出所有的语句执行次数,只需要计算执行次数最多的那一次,因为它一定是高阶项,这个里面语句3是执行次数最多的,显然可以看出执行次数为2*n*n,所以时间复杂度就是O(n^2);
(2) {x++;s=0;}
这是有两条基本语句,是常数,就算有100条语句,也是一个常数,100*1,时间复杂度是O(1),只要是常数,时间复杂度都是O(1)。
(3)for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
++x;a[i,j]=x;//3
}
}
分析这个时间复杂度的时候,当i为0 的时候,语句3执行了0次,i为1的时候,语句3执行了1次,i为2的时候,语句3执行了2次,规律就是i++的时候,执行次数是1,2,3,4...n-1,所以一共执行的次数是1+2+3+4+...+n-1;可以发现是一共等差数列,求出来的结果是(1+n-1)*(n-1)/2=(n^2-n)/2,所以它的时间复杂度是O(n^2)。可以和(1)比较一下,如果i和j都和n有关,很容易看出时间复杂度是O(n^2),但是如果i和n有关,j和i有关,时间复杂度也是O(n^2)。冒泡排序就是后面这种。
(4)
while((n%i)!=0&&i*1.0<sqrt(n)) //笔试题
i++;
if(i*1.0<sqrt(n))
{return true;}
else
{ return false;}
这个是求素数的函数,时间复杂度是O(n^(1/2))(就是根号n)
下面要说的就是一类函数的时间复杂度:递归
(4)
int Age(int n)//O(n)
{
if(n == 1)
{
return 10;
}
return Age(n-1)+2;//3
}
语句3是这样执行的,先执行n-1,然后n-2,然后n-4,n-5...3,2,1,可以倒过来看,1,2,3....n-2,n-1,这样是执行了n-2次,只要n,所以时间复杂度就是O(n)。
1.如果语句3换成Age(n-2)+2呢?
现在执行的顺序是n-2,n-4,n-6...7,5,3,1反过来看就是1,3,5,7...n-4,n-2,可以看出执行次数大概是n/2,系数不要,时间复杂度还是O(n)。
2.如果换成Age(n-3)+2呢?
和上面一样,只是系数变成了1/3,但是系数并不影响时间复杂度,所以时间复杂度还是O(n)。
可以看出递归中减法的就不会影响时间复杂度
3.
如果换成Age(n/2)+2呢?
执行的结果是n/2,n/4,n/8...8,4,2,1,反过来看就是1,2,4,8...n/8,n/4,n/2,n,一眼好像看不出来执行的次数,假设执行了x次,可以发现规律2^x=n; 所以n=log2(n);(这里代表的是log以2为底n的对数),所以时间复杂度就是O(log2(n))
这个的效率就要比上面的效率高的多了,如果要n为一万,n-2要执行5000次,但是n/2只需要执行13到14次就可以了,如果n为一亿,n-2要执行五千万次,n/2只要执行不到30次,所以数据越大,后面的执行效率就越高,数据结构中折半查找,快速排序,归并排序,堆排序都是用类似这种方法。
所以我们回到最开始的时候,就能理解,随着模块n的增大,算法的时间复杂度越低,算法的效率越高,所以衡量一个算法好坏,时间复杂度是不可或缺的参照。