常常说快速排序的算法时间复杂度为O(nlogn),但是这个值是怎么算出来的,为什么就是O(nlogn);很多书上一上来就大谈特谈那么多理论,我实在是受不了,我是看不懂,我不知道作者自己懂不懂,深刻的表示怀疑!
就拿这个logn来说,我隐隐记得在高中学的时候,这个底数省略的话就是默认10,查了资料也确实是10,但是貌似我们讲算法书上的意思都是以2为底,为什么他妈的书上不解释一下。
快速排序的时间复杂度为O(nlgn),即:每次都可以分为均匀两段,根据这个,推算出时间复杂度为O(nlgn).这个是如何推算出来的?
解释:
算法中log级别的时间复杂度都是由于使用了分治思想,这个底数直接由分治的复杂度决定,如果采用二分法,那么就会以2为底数,3分法就会以3为底数,不过无论底数是什么,log级别的渐进意义是一样的.也就是说该算法的时间复杂度的增长与处理数据多少的增长的关系是一样的.
综上所说:快速排序采用的是二分法,那么底数应该是2,那么应该是nlog2n;二分法能降低时间复杂度,将O(n)降到O(log2n);将O(n^2)降到O(nlog2n)
很多书上写成logN应该是指底数不确定,可能是2.3.4。。。。中的任何一个,但是我不知道他们这么写自己知道不,知道的话为什么就不提一下,难道谁都一看,哦这里的logN就是指log2N, 我估计他妈的他自己都不知道,还写书,受不了!
举几个例子:
1:
int num1,num2;
for(int i = 0; i < n; i++)
{
num1 + = 1;
for(int j = 1; j <= n; j* = 2)
{
num2+= num1;
}
}
分析:
1:语句 int num1,num2的频度为1;
2:语句 i=0;的频度为1;
3:i<n;i++;num1+=1;j= 1;的频度为n
4:语句j<=n;j*=2;num2+=num1;的频度为n*log2N;
T(n) = 2+4n+3n*log2N
5:
忽略了T(n)中的常量、低次幂和高次幂的系数
f(n) = n*log2n;
6:
lim(T(n)/f(n)) = (2+4n+3n*log2n) / (n*log2n)= 2*(1/n)*(1/log2n) + 4*(1/log2n) + 3
当n趋向于无穷大,1/n趋向于0,1/log2n趋向于0所以极限等于3。
T(n) = O(n*log2n)
2:
O(1)
交换i和j的内容
temp = i:
i = j;
j = temp;
这三个语句的频度为1,该程序的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为
常数阶,T(n) = O(1);如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条
语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。
3:
O(n^2)
sum = 0; //执行1传
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
{
sum++;//执行n^2次
}
}
T(n) = 1 + n^2 = O(n^2);
for(i = 1; i < n; i++)
{
y = y + 1;//执行1次
for(j = 0; j <= (2*n); j++)
{
x++;//执行 (n-1)*(2n+1) = 2n^2-n-1次;
}
}
T(n) = n-1+2n^2-n-1 = 2n^2 - 2;
T(n) = O(n^2);
4:
O(n)
a = 0; //执行1次
b = 1; //执行1次
for(i = 1; i <= n; i++) //执行n次
{
s = a + b;//执行n次
b = a;//执行n次
a = s;//执行n次
}
T(n) = 2+4n;
T(n) = O(n);
5:
O(log2n)
i=1; ①
while (i<=n)
i=i*2; ②
解:
语句1的频度是1,
语句2的频度是t, 则:2^t <=n; t<=log2n
考虑最坏情况,取最大值t=log2n,
T(n) = 1 + log2n
f(n) = log2n
lim(T(n)/f(n)) = 1/log2n + 1 = 1
T(n) = O(log2n)
时间复杂度计算的一些规则:
1) 加法规则
T(n,m) = T1(n) + T2(n) = O (max ( f(n), g(m) )
2) 乘法规则
T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))
3) 一个特例(问题规模为常量的时间复杂度)
在大O表示法里面有一个特例,如果T1(n) = O(c), c是一个与n无关的任意常数,T2(n) = O ( f(n) ) 则有
T(n) = T1(n) * T2(n) = O ( c*f(n) ) = O( f(n) )
也就是说,在大O表示法中,任何非0正常数都属于同一数量级,记为O(1)。
4) 一个经验规则
复杂度与时间效率的关系:
c < log2n < n < n*log2n < n2 < n3 < 2n < 3n < n! (c是一个常量)
|--------------------------|--------------------------|-------------|
较好 一般 较差
其中c是一个常量,如果一个算法的复杂度为c 、 log2n 、n 、 n*log2n,那么这个算法时间效率比较高 ,
如果是 2n , 3n ,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。
现在可以看看高大上的书上的理论知识了:
时间复杂度的定义
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,
T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号 ),
简称时间复杂度。
根据定义,可以归纳出基本的计算步骤
1. 计算出基本操作的执行次数T(n)
基本操作即算法中的每条语句(以;号作为分割),语句的执行次数也叫做语句的频度。在做算法分析时,一般默认为考虑最坏的情况。
2. 计算出T(n)的数量级
求T(n)的数量级,只要将T(n)进行如下一些操作:
忽略常量、低次幂和最高次幂的系数
令f(n)=T(n)的数量级。
3. 用大O来表示时间复杂度
当n趋近于无穷大时,如果lim(T(n)/f(n))的值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n))。
以上步骤可以简化为:
1. 找到执行次数最多的语句
2. 计算语句执行次数的数量级
3. 用大O来表示结果