算法效率的度量方法
事后统计方法: 主要是通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。
事前分析估算方法: 在计算机程序编写前,依据统计方法对算法进行估算。
程序运行所耗时间的因素:
- 算法采用的策略、方案
- 编译产生的代码质量
- 问题的输入规模
- 机器执行指令的速度
举例分析
第一种算法
int i, sum=0, n = 100; //执行1次
for( i=1 i <= n; i++ ) //执行了n+1次
{
sum = sum + 1 ; //执行n次
}
第二种算法
int i, sum = 0 , n = 100; //执行1次
sum = (1+n)*n/2; //执行1次
分析:
- 第一种算法执行了1+(n+1)+n=2n+2次。
- 第二种算法,执行1+1=2次 。
- 执行次数越少算法复杂度越小,算法越优,第二种算法比第一种算法更快
算法复杂度
算法复杂度分为时间复杂度和空间复杂度
- 时间复杂度 算法所花费的时间称为时间复杂度
- 空间复杂度 算法使用的空间资源称为空间复杂度
1.时间复杂度
定义: 在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度。其中f(n)是问题规n的某个函数。(重点: 执行次数==时间)
算法复杂度关系
在计算时间复杂度的时候,根据T(n)与n的最高阶数关系,整理了这些算法复杂度。
T(n)与 n 的最高阶数关系 | 名 称 |
---|---|
T(n) = O(1) | 常数阶 |
T(n) = O(n) | 线性阶 |
T(n) = O(n^2) | 平方阶 |
T(n) = O(n^3) | 立方阶 |
T(n) = O(2*n) | 指数阶 |
T(n) = O(logn) | 对数阶 |
T(n) = O(nlogn) | nlogn阶 |
大O阶的推导方法
- 用常数1取代运行时间中的所有加法常数。
- 在修改后的运行次数函数中,只保留最高阶项。
- 如果最高阶项存在且不是1,则出去其常系数,得到的结果就是大O阶。
程序分析推导时间复杂度:
程序段1:
int a = 100; //执行1次
int b = 200; //执行1次
int sum = a + b; //执行1次
printf ("%d\n",sum); //执行1次
上述程序段有4行代码,每一行执行1次,共执行4次,f(n)=4,即T(n)=O(4),根据推导方法中的第一条,将常数项以1代替,在保留其最高阶项时,发现其没有最高阶项,则得出T(n)=O(1),因此该算法时间复杂度为O(1),为常数阶。
程序段2:
void func()
{
int i, sum = 0; //执行1次
for ( i = 0; i <= 100; i++ )
{
sum +=i; //执行n次
}
printf("%d\n",sum); //执行1次
}
该程序段的执行次数为1+n+1,则f(n)=n+2,即T(n)=O(n+2)。然后将常数项以1替换,且只保留最高阶,则得出T(n)=O(n),因此该算法时间复杂度为O(n),为线性阶
程序段3:
void func()
{
int i = 1;
do
{
i * = 2;
}
while(i<n);
}
在这个程序段中,当i<n时,循环结束。如果循环了f(n)次,则2^f(n)=n,即f(n)=log2n,T(n)=O(log2n)。然后消除常系数,保留最高项,最后得出T(n)=O(logn),为对数阶。
常见的时间复杂度
常见的时间复杂度所耗费的时间从小到大依次是:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n !) < O(n^n)
2.空间复杂度
定义: 空间复杂度是对一个算法在运行过程中所占存储空间大小的度量,一般也作为问题规模n的函数,以数量级形式给出。
计算公式: S(n) = O(f(n))
一个算法的存储量包括输入数据所占空间、程序本身所占空间和辅助变量所占空间。在对算法进行分析时,只考虑辅助变量所占空间。
注:
1、通常都是用“时间复杂度”来指运行时间的需求,用“空间复杂度”指空间需求。
2、当直接要让我们求“复杂度”时,通常指的是时间复杂度。
3、时间复杂度的追求更是属于算法的潮流!