需要的时间资源的量称为时间复杂度,T=T(N,I)
需要的空间资源的量称为空间复杂度,T=T(N,I)
N代表问题的规模,I代表输入(实例)
空间复杂度与时间复杂度的分析方法类同,主要讨论时间复杂度。
例如:
void insertion_sort(Type *a,int n)
{Type key; // cost timesfor(int i=1;i<n;i++) // c1 n{ key=a[i]; // c2 n-1int j=i-1; // c3 n-1while(j>=0&&a[j]>key) // c4 sum of ti{a[j+1]=a[j]; // c5 sum of (ti-1)j--; // c6 sum of (ti-1)}a[j+1]=key; // c7 n-1}
}
以上的代码在最好情况下,ti=1,for 1<=i<n;
T(n)=c1*n+c2*(n-1)+c3*(n-1)+c4*(n-1)+c7*(n-1)
=(c1+c2+c3+c4+c7)*n-(c2+c3+c4+c7)
以上的代码在最坏的情况下 ti = i+1,for 1<=i<n;
T(n)=c1*n+c2*(n-1)+c3*(n-1)+c4(n(n+1)/2-1)+c5(n(n-1)/2+c6(n(n-1)/2)+c7(n-1)
=(c4+c5+c6)/2*n*n+(c1+c2+c3+(c4-c5-c6)/2+c7)*n-(c2+c3+c4+c7)
算法复杂性在渐进意义下的阶:
渐进意义下的记号:O,Ω,θ,o , ω
g(n)是定义在正数集上的正函数,T(n)为算法的时间复杂性,n是数据规模
(1)渐进上届记号O:
若是T(n) = O(g(n))
含义:算法在任何实例情况下,其时间复杂性的阶不超过g(n)的阶
即: lim(T(n)/g(n) = c != 0 , c为常数
如插入排序:lim(T(n)/(n*n)=(c4+c5+c6)/2为常数,故T(n)=O(n*n)
(2)渐进下届记号Ω
若T(n)=Ω(g(n))
含义:算法在任何实例情况下,其时间复杂性的解不低于g(n)的阶
即:lim(T(n)/g(n)) = c = 0,c为常数。
如插入排序:lim(T(n)/n)=c1+c2+c3+c4+c7为常数,故T(n)=Ω(n)
(3)记号θ
举例有一个算法A:最坏情况:T=c1*n*n + n + 4
最好情况:T=c2*n*n
存在g(n)=n*n,有T(n)=Ω(g(n))和T(n)=O(g(n))
因此 T(n) = θ(g(n)) = θ(n*n)
(4)非紧渐上界记号o
若T(n)=o(g(n))
含义:算法在任何实例情况下,其算法时间复杂性的阶小于g(n)的阶
即lim(T(n)/g(n)) = 0
举例:g(n)=n*n , T(n) = c2*n*logn -->T(n) = o(n*n)
(5)非紧渐进下届记号 ω
若 T(n)= ω(g(n))
含义:算法在任何实例情况下,其时间复杂性的阶大于g(n)的阶
即:lim(T(n)/g(n) = ∞
举例:g(n) = n,T(n)=c1*n*logn --> T(n) = ω(n)
void insertion_sort(Type *a,int n)
{Type key; for(int i=1;i<n;i++) { key=a[i]; int j=i-1; while(j>=0&&a[j]>key) {a[j+1]=a[j]; j--; }a[j+1]=key; }
}
以上意义下的阶层,其中O,Ω有等于关系,而o , ω没有等于关系。
算法的O记号的快速分析步骤:
(1)找出算法最坏情况下被执行次数最多的代码段,一般是循环嵌套次数最多的循环体
(2)计算这部分指令被执行的次数。
T(n)=1+2+......+n-1 = n(n-1)/2 = n*n/2-n/2 -->n*n (去低阶层,高阶层系数变1)
因此该算法的时间复杂性 T(n) = O(n*n)
例如:顺序搜索算法
temalate<calss Tyape>
int serSearch(Tyae *a,int n,Tyae k)
{for (int i=0;i<n;i++){if(a[i]==k)return i;}return -1;
}
以上的代码:
T(n) = max { T(I) | size(I)=n }=n -->T(n)=O(n)
T(n) = min { T(I) | size(I)=n }=1 -->T(n) =Ω(n)
常见的复杂性函数 C , logn , n , n*n , n*n*n , 2^n , n!
问题的计算时间下界为Ω(f(n)),则计算时间复杂性为O(f(n))的算法是最优的。
例如,基于比较的排序算法的计算时间下界为Ω(nlogn)