您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法学习笔记(二)

2016-02-26 10:45 323 查看
算法效率的度量方法:
事后统计法:通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。缺陷:必须依据算法事先编制好测试程序,通常需要花费大量时间和精力。不同测试环境差别也很大。

事前分析估算法:在计算机程序编写签,依据统计方法对算法进行估算。

高级语言编写的程序在计算机上运行时所耗的时间取决于下列因素:
算法采用的策略,方案

编译产生的代码质量

问题的输入规模

机器执行指令的速度

研究算法的复杂度,侧重的是研究算法随着输入规模扩大增长量的一个抽象,而不是精确地定位需要执行多少次。在分析一个算法的运行时间时,重要的是把基本操作的数量和输入模式关联起来。

函数渐进增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐近快于g(n)。

判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注主项(最高项)的阶数。

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

用大写O()来体现算法时间复杂度的记法,我们称之为大O记法。

一般情况下,随着输入规模n的增大,T(n)增长最慢的算法为最优算法。

如何分析一个算法的时间复杂度:
用常数1取代运行时间中的所有加法常数

在修改后的运行次数函数中,只保留最高阶项

如果最高阶项存在且不是1,则去除与这个项相乘的常数

得到最后的结果就是大O阶

int sum = 0, n = 100;
printf("aaaaaaaaaaaa\n");
printf("aaaaaaaaaaaa\n");
printf("aaaaaaaaaaaa\n");
printf("aaaaaaaaaaaa\n");
printf("aaaaaaaaaaaa\n");
printf("aaaaaaaaaaaa\n");
sum = (1+n)*n/2
//这段代码的时间复杂度为O(1),因为这段代码执行了8次,没有与n相关,常数都简化为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++) {
printf("aaaaaaaaaaaa\n");
}
}


上面这段代码的时间复杂度为O(n²)。

int i,j,n = 100;
for(i = 0; i < n; i++) {
for(j = i; j < n; j++) {
pringtf("aaaaaaaaaaaaaa\n");
}
}


分析,由于当i=0时,内循环执行了n次,当i=1时,内循环则执行n-1次。。。。。。当i=n-1时,内循环执行1次,所以总的执行次数应该是n+(n-1)+(n-2)+...+1=n(n+1)/2用上面的简化方法来简化½n²+½n,这个式子中没有常数项不用考虑第一条,根据第二条只保留最高项,去掉½n这一项,根据第三条去掉与最高项相乘的常数½,最终得到O(n²)

对数阶

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


由于每次i*2之后就距离n更近一步,假设有x个2相乘后大于或等于n,则会退出循环。于是由2x=n得到x=log2n,所以这个循环的时间复杂度为O(logn)。

int i,j;
for(i = 0; i < b; i++) {
function(i);
}

void function(int count) {
printf("%d",count);
}


function函数的时间复杂度是O(1),所以整体的时间复杂度就是循环的次数O(n)。

int i,j;
for(i = 0; i < b; i++) {
function(i);
}

void function(int count) {
int j;
for (j = count; j < n;j++) {
printf("%d",j);
}
}


和平方阶中第二个例子一样,function内部的循环次数随count的增加而减少,所以根据方法简化后的时间复杂度为O(n²)

n++;-------------------------------------执行1次
function(n);-----------------------------执行n²次
for(i = 0;i < n; i++) {------------------执行n²次
function(i);
}
for(i = 0;i < n; i++) {------------------执行n²次
for(j = i;j < n; j++) {
printf("%d",j);
}
}
void function(int count) {
int j;
for (j = count; j < n;j++) {
printf("%d",j);
}
}


上面几次操作是并列的,整体的执行次数应该是各个操作执行次数之和3n²+1,简化后得到时间复杂度为O(n²)

常见的时间复杂度

例子时间复杂度术语
5201314O(1)常数阶
3n+4O(n)线性阶
3n²+4n+5O(n²)平方阶
3log2n+4O(logn)对数阶
2n+3nlog2n+14O(nlogn)nlogn阶
n3+2n2+4n+6O(n3)立方阶
2nO(2n)指数阶
  17. 常见的时间复杂度所耗费的时间从小到大依次是

        O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < (nn)

  18. 平均运行时间是期望的运行时间

19. 最坏运行时间是一种保证。在应用中,这是一种最重要的需求,通常除非特别指定,我们提到的运行时间都是最坏情况的运行时间。

  20. 算法的空间复杂度通过计算算法所需的存储空间实现,算法的空间复杂度的计算公式记做S(n) = O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。

  21. 通常,我们都是用“时间复杂度”来指运行时间的需求,用“空间复杂度”指空间需求。

  22. 当直接让我们求“复杂度”时,通常指的是时间复杂度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: