一、时间复杂度:
1、时间频度(语句频度):
一个算法花费的时间与算法中语句的执行次数成正比,哪个算法中语句执行的次数多它花费的时间就越多,一个算法中语句执行的频次数成为语句频度或者时间频度。通常用T(n)表示。
2、渐进时间复杂度(时间复杂度):
T(n)中n称为问题的规模,当n不断变化,时间频度T(n)也会不断变化。存在f(n)在n趋近无穷大时,T(n)/f(n)的极限值为不等于0的常数,则称f(n)为T(n)的同数量级函数,记作:T(n)=O(f(n)),它称为算法的渐进时间复杂度,简称时间复杂度。(我不理解这段话什么意思,只是认为存在某个数学方面的函数表示程序的时间复杂度,记作:O(f(n)))
3、大O表示法:
用O(f(n))来表示程序时间复杂度的方法叫做大O表示法。
算法复杂度可以从最优、平均、最坏三种情况评估。为了避免程序遇到最坏情况影响运行,一般直接评估最坏情况的复杂度。
阶大O表示法中f(n)的值一般可取1(O(1)常数阶)、log2n(O(logn)对数级)、
n(O(n)线性阶)、n²(O(n²)平方阶)、n³(O(n³)立方阶)、2^n(O(2^n)指数阶)、n!(O(n!)阶乘)。
二、推导方法:
1.用常数1来取代运行时间中所有加法常数。
2.推导结果为多项式时,只保留最高阶项。
3.如果最高阶项系数不是1,则去除系数。
tips:递归的时间复杂度要考虑递归调用次数和每次递归的时间复杂度。每次递归内的时间复杂度乘以递归层数,主要看通过条件变量是否可以大幅度减少递归深度或者是每层递归内调用递归的次数。
例:常数阶
int sum = 0,n = 100; //执行一次
sum = (1+n)*n/2; //执行一次
printf("%d",sum) //执行一次
每条语句执行一次,相加为f(n)=3,常数级统统用1表示,既:O(1)。
线性阶:
for(int i=0;i<n;i++){
printf("%d\n",i);//常数阶
}
循环体内为常数阶f(n)=1;循环次数n,则O(f(n))=O(n),为线性阶。
对数阶:
int num=1;
while(num<n){
num*=2;//常数阶
}
代码中,num需乘以log2n次才能大于等于n,则时间复杂度为O(logn)。
平方阶和立方阶:
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
printf("%d\n",j)//常数阶
}
}
代码中为两层嵌套循环,最坏情况常数阶语句执行n*n次,既复杂度为O(n²);同理立方阶就是3层嵌套循环,推导结果只保留最高阶项即可。
三、时间复杂度比较:
计算10个元素 | 计算100个元素 | 计算1000个元素 | |
O(1) | 1 | 1 | 1 |
O(logn) | 3 | 6 | 9 |
O(n) | 10 | 100 | 1000 |
O(nlogn) | 30 | 600 | 9000 |
O(n²) | 100 | 10000 | 1000000 |
O(2^n) | 1024 | 1.26e+29 | 1.07e+307 |
O(n!) | 36288000 | 9.3e+157 | 4.02e+2567 |
常用的时间复杂度按照耗费的时间从小到大依次是:O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)
以上内容来源于:http://t.csdn.cn/UnmZv
四、空间复杂度:
1、简单来说:算法的空间复杂度指的是占用内存,cpu等计算机资源的程度。 2、具体点来解释就是:空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。比如直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。 而一般的递归算法就要有O(n)的空间复杂度了,因为每次递归都要存储返回信息。
五、通过最大子列和4种算法体验时间复杂度:
//D:\Documents\数据结构
//最大子列和
#include <stdio.h>
#include <stdlib.h>
int MaxSubsequenceSum1(int a[],int cnt);//算法1
int MaxSubsequenceSum2(int a[],int cnt);//算法2
int MaxSubsequenceSum3(int a[],int cnt);//算法3
int MaxSubsequenceSum4(int a[],int cnt);//算法4
int main(int argc,char const *argv[]){
int CNT=0;
scanf("%d",&CNT);
int a[CNT];
for(int i=0;i<CNT;i++){
scanf("%d",&a[i]);
}
int res=MaxSubsequenceSum1(a,CNT);
printf(":%d\n",res);
res=MaxSubsequenceSum2(a,CNT);
printf(":%d\n",res);
res=MaxSubsequenceSum3(a,CNT);
printf("F3:():%d\n",res);
res=MaxSubsequenceSum4(a,CNT);
printf(":%d\n",res);
return 0;
}
int MaxSubsequenceSum1(int a[],int cnt){//暴力求解时间复杂度O(n3)
int maxsum=-1;
int thissum=0;
int i,j,k,m=0,n=0;
/*三重for循环,时间复杂度为n3*/
for(i=0;i<cnt;i++){//i是子列起点
for(j=i;j<cnt;j++){//j是子列终点
for(thissum=0,k=i;k<=j;k++){//用k遍历子列每个元素并求和
thissum+=a[k];
}
if(thissum>maxsum){
maxsum=thissum;
m=i+1,n=k;
}
}
}
if(maxsum<0){
maxsum=m=0,n=cnt-1;
}
printf("F1:(%d-%d)",m,n);
return maxsum;
}
int MaxSubsequenceSum2(int a[],int cnt){//暴力求解,复杂度O(n2)
int maxsum=-1,thissum=0;
int i,j,m=0,n=0;
for(i=0;i<cnt;i++){
for(thissum=0,j=i;j<cnt;j++){
thissum+=a[j];
if(thissum>maxsum){
maxsum=thissum;
m=i+1;n=j+1;
}
}
}
if(maxsum<0){
maxsum=m=0,n=cnt-1;
}
printf("F2:(%d-%d)",m,n);
return maxsum;
}
int MaxSubsequenceSum3(int a[],int cnt){//分治法求最大子列和(递归),时间复杂度为O(nlogn)
int res=0;
if(cnt==1){
res=a[0];
}else if(cnt>1){
int *pl=a,*pr=a+cnt/2;
int lmax=MaxSubsequenceSum3(pl,cnt/2);
int rmax=MaxSubsequenceSum3(pr,cnt-cnt/2);
int mmax=0;
int i=0,ltemp=0,rtemp=0,thissum=0;
for(ltemp=0,thissum=0,i=cnt/2-1;i>=0;i--){
thissum+=pl[i];
if(thissum>ltemp)ltemp=thissum;
}
for(rtemp=0,thissum=0,i=0;i<cnt-cnt/2;i++){
thissum+=pr[i];
if(thissum>rtemp)rtemp=thissum;
}
mmax=ltemp+rtemp;
res=(lmax>rmax?lmax:rmax)>mmax?(lmax>rmax?lmax:rmax):mmax;
}
return res;
}//递归深度logn;每次递归次数,复杂度2^logn=n,两个for循环(logn+logn)*(n-1),整体复杂度为n*logn
int MaxSubsequenceSum4(int a[],int cnt){//在线求解法,复杂度为O(n);
int thisSum=0,MaxSum=-1;
int m=0,n=0,flag=0;
for(int i=0;i<cnt;i++){
if(flag==0){
m=i+1;
flag=1;
}
thisSum+=a[i];
if(thisSum<0){
thisSum=0;
flag=0;
}else if(thisSum>MaxSum){
MaxSum=thisSum;
n=i+1;
}
}
if(MaxSum==-1){
MaxSum=m=0,n=cnt-1;
}
printf("F4:(%d-%d)",m,n);
return MaxSum;
}