算法效率
算法效率是指算法执行的时间,算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量。
算法效率度量方法
- 事后统计法:利用计算机计时器,计算程序运行时间(缺陷:必须依据算法实现编制好测试程序,并且不同测试环境差别大)
- 事前分析法:在计算机程序编写前,依据统计方法对算法进行估算
- 程序消耗时间取决于
- 算法采用的策略和方案
- 编译产生的代码质量(软件)
- 问题输入规模
- 机器执行指令速度(硬件)
研究算法复杂度,侧重研究算法随着输入规模扩大增长量的一个抽象,而不是精确的定位多少次。
即分析算法运行时间,重要的是将基本操作的数量和输入规模关联起来
算法的时间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n) = O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。
T(n) = O(f(n))的表示方法叫大O记法。
一般情况下,随输入规模n增大,T(n)增长最慢算法为最优算法。
很容易理解,当T(n)中输入规模n越大T(n)即语句执行次数任然变化不大是,该算法的时间效率肯定越高
- 分析一个算法时间复杂度
- 用常数1取代运行时间中所有加法常数
- 在修改后运行次数函数中,只保留最高阶项
- 如果最高阶项存在且不是1,则去除与这个项相乘的常数,得到的结果就是大O阶
综上:一个循环的时间复杂度等于循环体复杂度乘以该循环运行的次数
常见的时间复杂度
T(n) | O(f(n)) | - |
---|---|---|
54646654631 | O(1) | 常数阶 |
5n+5 | O(n) | 线性阶 |
52+3n+21321 | O(n2) | 平凡阶 |
3log2n+32 | O(logn) | 对数阶 |
8n+4nlog2n+24041 | O(nlogn) | nlogn阶 |
n3+8n2+2n+1231 | O(n3) | 立方阶 |
2n | O(2n) | 指数阶 |
时间复杂度分析
int i,j,n=100;
for(i=0;i<n;i++)
{
for(j=1;j<n;j++)
{
printf("***");
}
}
/*由以上程序,可知程序循环总次数为
n+(n-1)+...+1
即(n(n+1))/2=0.5n^2+0.5n
所以该程序的时间复杂度为O(n^2)*/
int i=1,n=100;
while(i<n)
{
i=i*2;
}
/*分析该程序,设该程序一共循环了x次
2^x=n则可以知log2x=log2n
可得x=log2n
即该程序时间复杂度为O(logn)*/
int i,j;
for(i=0;i<n;i++)
{
function(i);
}
void function(int count)
{
printf("%d",count);
}
/*分析该程序,虽然调用了函数,
但是每次调用时执行一个语句,
因此,总体上该程序依然执行了n次
所以该程序的时间复杂度为O(n)*/
void func(int n)
{
int i=0,s=0;
while(s<n)
{
i++;
s=s+i;
}
}
/*分析该程序,设该程序循环结束时循环了x次,
则i的大小和x相等,所以有s=1+2+3+...+x=n,
此时有(x(x+1))/2=n;此时f(n)=根号n
所以时间复杂度为O(根号n)8/
常见的时间复杂度效率如下所示:
耗费时间: O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(n3) < O(2n) < O(n!) < O(nn)
最坏情况与平均情况
- 平均运行时间:期望的运行时间
- 最坏运行时间:是一种保证,除非特别指定,我们提到的运行时间都是最坏情况的运行时间
算法的空间复杂度
算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作:S(n)= O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。
一般来讲,我们分析算法的复杂度时候分析的都是算法的时间复杂度
总之,我们在分析算法复杂度时,是有迹可循的,只要计算出循环次数,再去除最高项和系数,得到问题规模n的函数f(n),该f(n)的增长率就可以替代算法执行时间的增长率,此时用大O记法即T(n) = O(f(n))便可表示出算法时间复杂度