算法复杂度-渐进分析 (Asymptotic Analysis)
渐进分析 Note
- 1. Introdiction
- 2. Big-Theta Notation - Θ\ThetaΘ
- 2.1 Example-Duplicate Detection
- 2.1.1 小实验(运行时间随规模增加的变化)
- 2.2一般描述算法复杂性的方法
- 2.2.1使用python计时器进行精确评估
- 2.2.2 计算代码中每一步的调用次数
- 2.2.2.1 对“调用次数”指标进行简化
- 2.3 Big theta-Θ\ThetaΘ
1. Introdiction
渐进分析 (Asymptotic Analysis)主要用于评估代码的性能
Old saying:
An engineer will do for a dim what any fool will do for a dollar.
垃圾的代码: 使用不合适的数据结构、复杂、缓慢、占用大量内存
好的代码:合适的数据结构、简洁、高效、使用合理的内存开销
2. Big-Theta Notation - Θ\ThetaΘ
2.1 Example-Duplicate Detection
考虑分析在如下的列表中,查找出重复元素的两种方法的算法复杂度:
-3 | -1 | 2 | 4 | 4 | 8 | 12 |
---|
implimentation of comparing algorithm
Object: 查找array中是否存在重复的元素
Determine if their is any duplicates in the array。
一个基本的想法是考虑所有可能的情况
A silly method
def sillySearch(x):OperationCount = 0print('I compare every possible pair!')lengthOfX = len(x)for _ in range(lengthOfX):currentA = x[_]for i in range(_+1,lengthOfX):OperationCount +=1print("Comparing ",str(x[_])+"=="+str(x[i]),"Operation Count: ",str(OperationCount))if x[_]==x[i]:print(str(x[_])+"="+str(x[i]))return True
程序输出:
I compare every possible pair!
Comparing -3==-1 Operation Count: 1
Comparing -3==2 Operation Count: 2
Comparing -3==4 Operation Count: 3
Comparing -3==4 Operation Count: 4
Comparing -3==8 Operation Count: 5
Comparing -3==12 Operation Count: 6
Comparing -1==2 Operation Count: 7
Comparing -1==4 Operation Count: 8
Comparing -1==4 Operation Count: 9
Comparing -1==8 Operation Count: 10
Comparing -1==12 Operation Count: 11
Comparing 2==4 Operation Count: 12
Comparing 2==4 Operation Count: 13
Comparing 2==8 Operation Count: 14
Comparing 2==12 Operation Count: 15
Comparing 4==4 Operation Count: 16
4=4
0:00:00.000192
[Finished in 1.9s]
一个更好的方法是只考虑相邻的情况
# a little bit cleverer method
# only consider the neighboring duplication
def betterSearch(x):OperationCount = 0print('I compare neighboring pairs!')lengthOfX = len(x)for _ in range(lengthOfX):currentA = x[_]OperationCount +=1print("Comparing ",str(x[_])+"=="+str(x[_+1]),"Operation Count: ",str(OperationCount))if x[_]==x[_+1]:print(str(x[_])+"="+str(x[_+1]))return True
程序输出:
I compare neighboring pairs!
Comparing -3==-1 Operation Count: 1
Comparing -1==2 Operation Count: 2
Comparing 2==4 Operation Count: 3
Comparing 4==4 Operation Count: 4
4=4
0:00:00.000059
[Finished in 1.7s]
记nnn为比较(======)的次数。
比较silly的baseline方法用了192个单位时间。n=16n=16n=16
改进的方法用了59个单位时间.n=4n=4n=4
where nnn is the count of the operating steps
2.1.1 小实验(运行时间随规模增加的变化)
在最坏的情况下(把重复项放到数组x的末尾),两种查重算法的运行时间(ms)与数组xxx的长度的关系。可见随着数组长度增加,silly方法的运行情况指数级恶化。
但是,在最好的情况下(数组中所有元素相同),二者的表现相差不大:
此时用x = [0]*N
对数组x 进行初始化
测试并绘图使用的源代码如下:
# A silly method
def sillySearch(x):OperationCount = 0# print('I compare every possible pair!')lengthOfX = len(x)for _ in range(lengthOfX):currentA = x[_]for i in range(_+1,lengthOfX):OperationCount +=1# print("Comparing if x[_]==x[i]:return True# a little bit cleverer method
# only consider the neighboring duplication
def betterSearch(x):OperationCount = 0# print('I compare neighboring pairs!')lengthOfX = len(x)for _ in range(lengthOfX-1):currentA = x[_]OperationCount +=1if x[_]==x[_+1]:# print(str(x[_])+"="+str(x[_+1]))return Trueimport datetime
from matplotlib import pyplot as plt
# x = [-3,-1,2,4,4,8,12]sillyRecorder = []
betterRecorder = []
#test silly
for N in range(1,1000,100):x = list(range(0,N-1))x.append(N-2)start = datetime.datetime.now()sillySearch(x)# do somethingend = datetime.datetime.now()sillyRecorder.append((end-start).microseconds)
for N in range(1,1000,100):x = list(range(0,N-1))x.append(N-2)start = datetime.datetime.now()betterSearch(x)end = datetime.datetime.now()betterRecorder.append((end-start).microseconds)plt.plot(sillyRecorder)
plt.plot(betterRecorder)
plt.legend(['silly','better'])
plt.show()
plt.xlabel('length of array')
plt.xlabel('Running Time (/ms)')
print(sillyRecorder)
2.2一般描述算法复杂性的方法
为了描绘一个算法的复杂性,需要建立一种同时具有简单(simple)和数学严谨性(mathematically rigious)的描述方法,使得上述两种算法的复杂度一目了然。首先来看一下常见的描述算法性能的方法,然后逐渐过渡到Big-Theta Notation - Θ\ThetaΘ。
2.2.1使用python计时器进行精确评估
1:对python文件的运行时间进行计时
在终端中输入:
>> time python 文件名
2: 对指定代码块的运行时间进行计时
import datetime
start = datetime.datetime.now()
代码块
end = datetime.datetime.now()
print (end-start)
2.2.2 计算代码中每一步的调用次数
考虑到算法规模为NNN的情况(即待查找的list长度为NNN),
对于比较“笨”的这种算法:
def sillySearch(x):lengthOfX = len(x)for _ in range(lengthOfX):currentA = x[_]for i in range(_+1,lengthOfX):OperationCount +=1if x[_]==x[i]:print(str(x[_])+"="+str(x[i]))return True
各个功能块的执行次数、最好的情况到最差的情况如下:
Operation | Count |
---|---|
range calls | 2 to N+1N+1N+1 |
len calls | 2 to N+1N+1N+1 |
_ assignments | 1 to N−1N-1N−1 |
j assignments | 1 to N2−N2\frac{N^2-N}{2}2N2−N |
equals(==) | 1 to N2−N2\frac{N^2-N}{2}2N2−N |
array access) | 2 to N2−NN^2-NN2−N |
对于比较聪明的算法:
# a little bit cleverer method
# only consider the neighboring duplication
def betterSearch(x):OperationCount = 0lengthOfX = len(x)for _ in range(lengthOfX):currentA = x[_]OperationCount +=1if x[_]==x[_+1]:return True
各个功能块的执行次数、最好的情况到最差的情况如下:
Operation | Count |
---|---|
range calls | 1 |
len calls | 1 |
_ assignments | 1 to N−1N-1N−1 |
equals(==) | 1 to N−1N-1N−1 |
array access) | 2 to 2N−22N-22N−2 |
2.2.2.1 对“调用次数”指标进行简化
我们可以依据以下规则对上述的评估方式进行适当简化:
- 只考虑最差的情况(Only consider the worst case)
- 选择具有代表性的操作(Representative Operation)
- 忽略低次项(Ignore lower order terms)
- 忽略乘法计算的常系数 (Ignore multiplicative constant)
假设说有这么一个算法的操作计数表:
Operation | Count |
---|---|
Op_1 | 1 |
Op_2 | 1 to NNN |
Op_3 | 1 to N2−N2\frac{N^2-N}{2}2N2−N |
Op_4 | 0 to N2+3N+22\frac{N^2+3N+2}{2}2N2+3N+2 |
这个表可以被进一步简化为:
Operation | Count |
---|---|
Op_3 | N2N^2N2 |
于是现在就有以一种基于数学假设的更严谨的方式,使用N2N^2N2来刻画这个算法的复杂度。
实际上一个算法的复杂度取决于最最糟糕的情况下,操作复杂度增长的数量级。
2.3 Big theta-Θ\ThetaΘ
-Example: Q(N)=3N3+N2Q(N)=3N^3+N^2Q(N)=3N3+N2
-Order of growth: N3N^3N3
function | Order of growth |
---|---|
N3+3N4N^3+3N^4N3+3N4 | N4N^4N4 |
1N+N3\frac{1}{N}+N^3N1+N3 | N3N^3N3 |
1N+5\frac{1}{N}+5N1+5 | 1 |
NeN+NNe^N+NNeN+N | NeNNe^NNeN |
40∗sin(N)+4N240*sin(N)+4N^240∗sin(N)+4N2 | N2N^2N2 |
Big-Theta的定义:
假设我们有一个函数R(N)R(N)R(N),有一个增长的order f(N)f(N)f(N)(order of growth)。
在“Big-Theta” 的标记方式里,我们把这个关系写为:
R(N)∈Θ(f(N))R(N)\in \Theta(f(N))R(N)∈Θ(f(N))
例如:
- N3+3N4∈Θ(N4)N^3+3N^4\in\Theta(N^4)N3+3N4∈Θ(N4)
- 1N+N3∈Θ(N3)\frac{1}{N}+N^3\in \Theta(N^3)N1+N3∈Θ(N3)
- 1N+5∈Θ(1)\frac{1}{N}+5\in\Theta(1)N1+5∈Θ(1)
- NeN+N∈Θ(NeN)Ne^N+N\in\Theta(Ne^N)NeN+N∈Θ(NeN)
- 40∗sin(N)+4N2∈Θ(N2)40*sin(N)+4N^2\in\Theta(N^2)40∗sin(N)+4N2∈Θ(N2)
注意,有的情况下,有人会选择将上述的∈\in∈换成===。
更具体而言,当我们说R(N)∈Θ(f(N))R(N)\in \Theta(f(N))R(N)∈Θ(f(N))的时候,等价于存在两个为正的常数
k1k_1k1和k2k_2k2, 于是有:
k1⋅f(N)≤R(N)≤k2⋅f(N)k_1\cdot f(N)\leq R(N)\leq k_2\cdot f(N)k1⋅f(N)≤R(N)≤k2⋅f(N)
对于所有的NNN当N0≤NN_0 \leq NN0≤N时成立
算法复杂度-渐进分析 (Asymptotic Analysis)相关推荐
- 算法复杂度-渐进分析
算法复杂度-渐进分析 渐进表达式的定义 渐进上界 大OOO O(g(n))={f(n):∃c>0,n0>0.s.t.∀n≥n0,0≤f(n)≤cg(n)}O(g(n)) = \{f(n): ...
- 数据结构 | 十大排序超硬核八万字详解【附动图演示、算法复杂度性能分析】
写在前面 2023年的第一篇博客,在这里先祝大家兔年快乐
- 【数据结构】算法的渐进分析-渐进时间复杂度
算法的渐进分析(asymptotic algorithm analysis)简称算法分析.算法分析直接与它所求解的问题的规模 n 有关,因此,通常将问题规模作为分析的参数,求算法的时间和空间开销与问 ...
- 二分检索用途及复杂性_二分查找和三分查找哪个快?算法复杂度与常数无关?复杂度分析的常见误区...
还记得两三年前,我初看一本算法书,看到二分查找算法的复杂度时,我发现了了不得的东西:二分查找每次查询范围减少一半,需要查询的次数是 ,它的复杂度是 . 我把它改成三分查找,每次查询两个数字与我的目标数 ...
- 算法复杂度及渐进符号
算法复杂度及渐进符号 一.算法复杂度 每一个程序在运行时,都需要占用一定的计算机资源,比如内存,磁盘,这些称之为空间. 计算过程中需要判断,循环执行某些逻辑,周而反复,这些是时间. 那么我们可以通过算 ...
- 算法时间复杂度的渐进表示法 + 分析窍门
如果算法里面只有加减法,则算法时间算加减法的次数. 如果算法里面包含加法和乘法,则算法时间一般只算乘法次数,因为计算机计算加减法很快,可忽略. 问题:什么是好的算法? 一个程序的运行时间,依赖与算法的 ...
- Asymptotic Analysis——渐近分析
上图主要介绍的是渐进分析的动机是什么. 高级推理算法的"灵魂"(翻译水平有限,不知道合适不合适,若有好的翻译请告诉我,或者你直接看英文原版吧) 不关注架构/语言/编译器的相关细节( ...
- 图的链接分析 (link analysis): PageRank 算法
目录 PageRank 的定义 前置知识 基本想法 PageRank 的基本定义 PageRank 的一般定义 PageRank 的计算 代数算法 迭代算法 幂法 (power method) Why ...
- 【天赢金创】算法复杂度分析
原文:http://www.cnblogs.com/gaochundong/p/complexity_of_algorithms.html 为什么要进行算法分析? 预测算法所需的资源 计算时间(CPU ...
- 算法复杂度分析(下)
前一篇文章算法复杂度分析(上)讲述了复杂度的大 O 表示法和几个分析原则,这篇文章我们来讲讲另外几种复杂度,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度 ...
最新文章
- 如何对DevOps数据库进行源代码控制
- eclipse配置maven + 创建maven项目
- ubuntu 64 12.04 oracle,ubuntu server 12.04 x86_64 下安装oracle xe 11 x86_64
- linux系统lsmod命令,linux lsmod命令 及相关信息
- [转载]使用消息队列实现分布式事务-公认较为理想的分布式事务解决方案
- 分布式文件系统-HDFS( HDFS全称是Hadoop Distributed System)
- Illustrator 教程,如何在 Illustrator 中创建标签?
- BZOJ1086 [SCOI2005]王室联邦(树分块)
- modbus tcp主站和从站_图文讲解PLC通讯MODBUS协议的应用及编程
- 追求代码质量: 使用 TestNG-Abbot 实现自动化 GUI 测试
- C++实现金山打字通助手
- unity 摄像头跟着鼠标移动_lwj_unity_模拟第一人称摄像机前后左右移动、摄像机随鼠标移动旋转、鼠标点击添加物体...
- 【最大公约数】欧几里得算法
- V2X方案之OBU介绍
- md4 java_求MD4 java实现的代码
- aspen压缩因子_ASPEN PLUS的物性数据库及其应用.pdf
- 新型病毒DoubleAgent 先入侵杀毒软件
- MySQL||主键(primary key)及主键约束
- 你处在人生的哪个阶段
- HR在线招人,快甩简历啦
热门文章
- stm32 带通滤波器_带通滤波器详解_带通滤波器工作原理_带通滤波器原理图
- access数据库应用系统客观题_Access数据库程序设计模拟题
- 【软件体系结构】软件体系结构风格
- 谷歌浏览器翻译栏_将Google翻译栏添加到您喜欢的浏览器
- 消息钩子函数入门篇(1)--基础知识
- 设计文档应该怎么写?
- 网赚项目之站群第一课如何利用站群快速赚钱
- 在Ubuntu中下载github上的文件
- \t\t产后饮食标准 饮食原则 最适合新妈妈吃的菜 饮食秘诀 禁忌
- 甘特图首选解决方案-世界级甘特图控件(XGANTT) - XGantt甘特图中文官方网站