算法效率的度量

本文探讨了算法效率的度量方法,重点在于时间复杂度和空间复杂度。通过对不同阶函数的分析,如常数阶、线性阶、平方阶和对数阶,阐述了大O记法在确定算法执行时间增长率中的应用。同时,文章提到了最坏情况和平均情况的考虑,以及如何分析函数调用的时间复杂度。此外,还简述了空间复杂度的概念,强调了算法设计时对时间和空间资源的考量。
摘要由CSDN通过智能技术生成

算法效率的度量方法

算法要尽可能的提高效率,一般指的是算法的执行时间
对时间的测定有两种方法:
* 事后统计方法:这种方法主要是通过设计好的测试程序和数据,利用计算机对不同算法编制的程序的运行时间作比较,从而确定算法效率的高低。(有很大缺陷)
* 事前分析估算方法:在计算机程序编写前,依据统计方法对算法进行估算。经过总结,一个高级语言编写的程序在计算机上运行是所消耗的时间取决于下列因素:
1. 算法所采用的方案策略
2. 编译产生的代码质量
3. 输入规模
4. 机器执行指令的速度

我们在分析一个算法的运行时间时,总要的是吧基本操作的数量和输入模式关联起来

函数的渐进增长

假设两个算法的输入规模都是n,算法A要做2n+3次操作,可以理解为:先进行一个n次的循环,再进行一个n次的循环,最后有3次运算。算法B要做3n+1次操作,理解同上,那么哪一个更快?

规模算法A1(2n+3)算法A2(2n)算法B1(3n+1)算法B2(3n)
n=15243
n=27476
n=396109
n=1023203130
n=100203200301300

随着n的增加,可以看出A算法更优。
函数的渐进增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,那么我们说f(n)的增长渐进快于g(n)。(加法常数可以忽略)
我们可以以3n+1,2n^2,n^3为例再次进行实验得到下面的结论:
算法效率主要和主项(最高次项)的阶数相关。
注意不要以偏概全,实验数据要丰富。

算法时间复杂度

在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)的随n的变化情况并确定T(n)的数量级。算法时间复杂度,也就是算法的时间量度,记作:T(n) = O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。

这样用大写O()来体现算法时间复杂度的记法,我们称之为大O记法。
一般情况下,随着输入规模n的增大,T(n)增长最慢的算法为最优算法。

推导大O阶方法
  • 用常数1取代运行时间中的所有常数
  • 再修改后的运行次数函数中,只保留最高阶项
  • 如果最最高阶想存在且不是1,则去除与这个项相乘的常数
  • 得到的最后结果就是大O阶
常数阶
int sum = 0,n = 100;
cout<<"I am a students";
cout<<"这是数据结构与算法课程";
sun = (1+n)*n/2;

这段代码的大O阶是多少呢,这个只有一条和n相关的指令,很明显是O(1)。

线性阶

一般含有非浅套循环涉及线性阶,线性阶就是随着问题规模n的扩大,对应计算次数呈直线增长。

int i ,n =100, sum = 0;
for( i = 0;i<n;i++){
    sum = sum + i;
}
//上面这段代码,循环的时间复杂度为O(n),因为循环体中的代码需要执行n次。
平方阶

如果循环是嵌套的,代码如下

int i,j,n = 100;
for(i = 0; i<n; i++){
    for(j = 0;j<n;j++){
        cout<<"数据结构与算法";
    }
}
//这段代码的时间复杂度为O(n^2)

我们可以总结出,循环的时间复杂度等于循环体的复杂度乘改循环运行的次数
更改一下代码

int i,j,n = 100;
for(i = 0; i<n; i++){
    for(j = i;j<n;j++){
        cout<<"数据结构与算法";
    }
}

这个总的执行次数应该是n+(n-1)+(n-2)+…+1 = n(n+1)/2 = n^2/2 + n/2
按照我们的规律,第一条忽略,因为没有常数相加;第二条只保留最高项,所以去掉n/2;第三条,去除与最高项相乘的常数,最终得到O(n^2)。

对数阶
int i = 1,n = 100;
while(i<n){
    i = i*2;
}

由于是由2^x = n得到x = log~2~n,所以这个循环的时间复杂度为O(logn)。

函数调用的时间复杂度分析
int i ,j;
for(i = 0;i<n;i++){
    function(i);
}
void function(int count){
    cout<<count;
}

function的时间复杂度是O(1),所以循环的时间复杂度是O(n)
如果更改function如下:

void function(int count){
    int j;
    for(j = count;j<n;j++){
        cout<<j;
    }
}

这样就变成了O(n^2^)

void function(int count){
    int j;
    for(j = count;j<n;j++){
        cout<<j;
    }
}
n++;//执行一次
function(n);//n^2次
for(i = 0;i<n;i++){//n^2次
    function(i);
}
for(i= 0;i<n;i++){//n^2次
    for(j = i;j<n;j++){
        cout<<j;
    }
}

得到的复杂度是O(n^2^)

例子时间复杂度术语
123O(1)常数阶
3n+4O(n)线性阶
3n^2^+4nO(n^2^)平方阶
3log~2~n+4O(logn)对数阶
3nlog~2~n+4O(nlogn)nlogn阶
2^n^O(2^n^)指数阶

常用的时间复杂度所耗费的时间从小到大依次是:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2^) < O(n^3^) < O(2^n^) < O(n!) < O(n^n^)

最坏情况与平均情况

比如,当我们遍历一个数组来查找一个数字,最好的情况是第一个就找到O(1);最坏的情况是在最后O(n)

算法的空间复杂度

算法的空间复杂度通过计算算法所需的存储空间实现,算法的空间复杂度的计算公式记作S(n)=O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。
通常我们都是用”时间复杂度“来指运行时间的需求,使用“空间复杂度”指空间需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值