数据结构与算法学习笔记(二)
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阶
线性阶:一般含有非嵌套循环设计线性阶,线性阶就是随着问题规模n的扩大,对应计算次数呈直线增长。
上面这段代码的循环复杂度为O(n),因为循环体中的代码需要执行n次
平方阶
上面这段代码的时间复杂度为O(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²)
对数阶
由于每次i*2之后就距离n更近一步,假设有x个2相乘后大于或等于n,则会退出循环。于是由2x=n得到x=log2n,所以这个循环的时间复杂度为O(logn)。
function函数的时间复杂度是O(1),所以整体的时间复杂度就是循环的次数O(n)。
和平方阶中第二个例子一样,function内部的循环次数随count的增加而减少,所以根据方法简化后的时间复杂度为O(n²)
上面几次操作是并列的,整体的执行次数应该是各个操作执行次数之和3n²+1,简化后得到时间复杂度为O(n²)
常见的时间复杂度
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. 当直接让我们求“复杂度”时,通常指的是时间复杂度。
事后统计法:通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。缺陷:必须依据算法事先编制好测试程序,通常需要花费大量时间和精力。不同测试环境差别也很大。
事前分析估算法:在计算机程序编写签,依据统计方法对算法进行估算。
高级语言编写的程序在计算机上运行时所耗的时间取决于下列因素:
算法采用的策略,方案
编译产生的代码质量
问题的输入规模
机器执行指令的速度
研究算法的复杂度,侧重的是研究算法随着输入规模扩大增长量的一个抽象,而不是精确地定位需要执行多少次。在分析一个算法的运行时间时,重要的是把基本操作的数量和输入模式关联起来。
函数渐进增长:给定两个函数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²)
常见的时间复杂度
例子 | 时间复杂度 | 术语 |
5201314 | O(1) | 常数阶 |
3n+4 | O(n) | 线性阶 |
3n²+4n+5 | O(n²) | 平方阶 |
3log2n+4 | O(logn) | 对数阶 |
2n+3nlog2n+14 | O(nlogn) | nlogn阶 |
n3+2n2+4n+6 | O(n3) | 立方阶 |
2n | O(2n) | 指数阶 |
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. 当直接让我们求“复杂度”时,通常指的是时间复杂度。
相关文章推荐
- 慕课网----大话PHP设计模式 二(数据结构的php实现,链式操作,php魔方方法的使用)
- 算法竞赛入门经典(第二版)-刘汝佳-第六章 数据结构基础 习题(12/14)
- redis内部数据结构--简单动态字符串sds
- 数据结构-5
- 数据结构——二叉查找树
- 算法竞赛入门经典(第二版)-刘汝佳-第六章 数据结构基础 例题(17/22)
- 数据结构与算法复习
- hdu1828[扫描线矩形周长并]
- MySQL索引背后的数据结构及算法原理
- 数据结构总结(3)
- 栈和堆的数据结构的差异
- HDU3255[farm] (扫描线方体体积并)
- 数据结构之队列(六)
- 数据结构与算法基础(一)
- 数据结构总结(2)
- 第 10 章 数据结构
- 大话数据结构--第1章 数据结构绪论
- 数据结构与算法学习笔记(一)
- 数据结构复习之【排序】
- 数据结构总结(1)