如何理解算法中的渐进符号?

我们分析一个算法的时候,常常需要用到数学去描述其性能。最常用的的是?。比如在一段程序中有

For(I = 0,I < n ; I ++)

For(J = 0; j < n ; j++);

For (cnt = 0; cnt < n ; cnt ++);

我们会说其最坏情况是n^2+ n,这时候,实际上我们没有考虑机器因素,我们把每一条指令的执行时间都当做单位1来看,如果我们考虑到机器因素,比如在A机器上,每条指令执行的速度是c1,那么他的最坏情况是( n^2  +  n) / c1,而在机器B上,速度变成了c2,那么最坏情况变成了(n^2 + n) / c2,如果c1是10,而c2是20,那么我们就说:算法在机器A上面的性能比机器B上差?显然不是这样的,机器变差了但算法本身没有变差,所以说在不同的机器上跑同样的算法,最坏情况时间总是不一样的,我们得想方设法去除机器性能的影响,而只是去单单分析算法本身的优劣,以便于在具体量化算法性能的时候又能去除机器因素的影响,因为我们讲算法分析而不是计算机系统分析。于是有人发明了Θ符号。对于这个符号我们来看几个例子,再看定义

比如说 :

a * x ^2 + b * x + c = f(x);那么有Θ(x^2)= f(x).

a * x ^ 3 + b * x ^ 2 + c *x + d = f(x);那么有Θ(x ^ 3) = f(x).

也就是说它相当于取出f(x)的最高次项然后去掉其常数因子,然后放入Θ()中,而放入Θ()中又表示了什么呢?为了弄清楚这个问题,我们来看其定义:

注:在集合表示中“:”符号表示“满足于 …条件”

Θ(g(n)) = {f(n) : 存在某个常数c1,c2,和n0,使得当n >= n0时,有 0 <= c1 * g(n) <=f(n) <= c2 * g(n) }

从后面半句开始,“存在 n > n0,0<= c1 * g(n)”这里保证了g(n)是一个增函数。接着,有 c1 * g(n)<=  f(n)  <= c2 * g(n).在脑海里可以想象出来函数图像 [ c1 * g(n),c2 * g(n) ]这个区间实际上是摇摆的曲线,如果把g(n)看做是y = x这样的正比例函数,就是一个扇形是吧?一根曲线摇摆着,扫出一个扇形来。而f(n)就是这组成扇形的众多曲线中的一根!这里也就是说,无论g(n)是什么,总能有一个常数因子使得c1 * f(n) =g(n).再返回来原来的题目中去理解:

a * x ^2 + b * x + c = f(x);那么有Θ(x^2)= f(x),这里Θ(x^2)表示,在x趋于无穷大这个过程中,有一个常数c使得c * n^2 = a * x ^2 + b * x +c = f(x),也就是:同!阶!数!(见高数上);这样,我们用Θ()来描述先程序的性能n^2 + n变成了Θ(n ^ 2),这里表明,在n趋于无穷大的过程中,总有一个常数因子使得c * n^2 = n ^2 + n,这个常数因子c在上文中说到,由机器和其它非算法因素来决定。也就是说,我们用Θ(n
^ 2)来表示一个算法的性能的时候,我们就完全忽略了机器,只研究算法本身,它好像是说:无论你在什么机器上跑这个算法,只要输入规模足够大,你的性能都是n ^ 2的整数倍,至于是多少倍,由机器决定的,反正在同样的机器上,这个倍数是相等了。

你看,Θ(x^2)表示的不就是机器无关的,纯算法的性能了吗?原来的问题解决了。不过Θ(x^2)符号还使得我们只关注最高次幂,不去关注低次项,因为在n->无穷大的时候,低次项是没有意义的,因为此时只要n变化一点点,就足以抵消低次项的变化(其实还是同阶数)。所以我们知道,对于一个时间复杂度为Θ(x^2)的算法,它的时间性能是优于Θ(x^3)的算法的,这里我们没有考虑常数因子,即使Θ(x^3)的常数因子是10000000000000而Θ(x^2)的常数因子是1也没有关系,因为无论如何,总有一个值n0使得n越过这个点之后Θ(x^2)的算法总能打败Θ(x^3)的算法,也就是说使用了Θ这类的符号(渐进符号)去比较算法时间性能的时候,是与机器无关的,即使你在超级计算机上跑Θ(x^3)算法,只要输入规模和时间足够,跑Θ(x^2)算法的老式386机子总能打败超级计算机。类似于Θ符号我们引出了O符号(读作大o)。

O(g(n)) = {f(n) : 存在某个常数c,和n0,使得当n >= n0 时,有 0 <= f(n) <= c *g(n) }

这里我们就只关心最坏情况,我们在谈论一个算法的最坏情况时间复杂度的时候总是喜欢使用O符号,我通过前面的例子来说明这个O符号的作用。

For(I = 0,I < n ; I ++)

For(J = 0; j < n ; j++);

For (cnt = 0; cnt < n ; cnt ++);

这时候我们把机器执行的速度看做单位1,于是执行的时间是n^2 + n,我们会说,上面这个算法最坏情况时间复杂度是O(n^2),还是同样的目的,我们不去考虑机器本身的影响,因为机器执行的速度如果是c,那么时间也就是变成了(n^2 + n) / c,也只是常数因子的问题而已。在输入规模足够大的情况下,我们用O(n^ 2)来忽略机器的影响,只考虑算法本身的最坏情况,告诉别人: 嘿!无论你在什么机器上跑,你的最坏情况都不能比n ^ 2 这个值的x倍更坏啦。至于X倍是多少倍,反正我们只是研究算法的,只有做机器的人才知道X是多少倍,而我们比较算法的时候,不会在不同的机器上去测同样的算法然后拿来比较,往往在同样的机器上去考察一个算法,这时常数因子X是相等的,关心它也是多余的了,这就好比我们高考的时候每个人的分数都乘以10分然后再来报考,结果还不是一样?因为考大学是根据排名来录取的,所以对于算法也是一样的,我们只关注:“那个算法才是最好的?我们应该选择哪个算法?”这种比较性的问题。

————————————————————————上大人孔乙己 2014、11、23

时间: 2025-01-06 15:14:10

如何理解算法中的渐进符号?的相关文章

算法中的渐进记号

前言 在学习计算机算法时,知道插入排序的时间复杂度是O(n2),那O记号到底是什么意思呢?本文主要介绍几个算法分析时用到的记号. 大O记号 定义:O(g(n)) = { f(n) : 存在正常数c和n0 ,使对所有的n >= n0,都有 0 <= f(n) <= cg(n) }.大O记号给出函数的渐进上界. , 则可以表示为 f(n) = O(n2).证明: 要使得 0 <= f(n) <= cg(n) 存在c = 9/2 ,n0 = 1,使得对所有的n >= n0都有

算法分析中常用的几种渐进符号

在算法分析中,经常会遇到以下几种渐进符号 渐近精确界记号:ΘΘ(big-theta) 渐近上界记号?:OO(big-oh) 渐近下界记号?:ΩΩ(big-omege) 非渐近紧确上界:o(小-oh) 非渐近紧确下界:ω(小-omege) 下面对渐进符号进行详解: 大写O符号f(n)=O(g(n)),这里f(n)是分析出来算法的执行次数的函数,O的定义:   当且仅当存在正的常数c和n0,使得对于所有的n>=n0,有f(n)<=cg(n).这里cg(n)就是函数f(n)的上限.讲到这是不是很迷糊

深入理解计算机系统(2.5)------C语言中的有符号数和无符号数以及扩展和截断数字

上一篇博客我们讲解了计算机中整数的表示,包括无符号编码和补码编码,以及它们之间的互相转换,个人觉得那是非常重要的知识要点.这篇博客我们将介绍C语言中的有符号数和无符号数以及扩展和截断数字. 1.C语言中的有符号数和无符号数 上一篇博客我们给出了C语言中在32位机器和64位机器中支持的整型类型数据,我们这里只给出32位机器上的: 尽管 C 语言标准没有指定有符号数要采用某种编码表示,但是几乎所有的机器都使用补码.通常大多数数字是默认有符号的,比如当声明一个像12345或者0xABC这样的常量的时候

关于DPM(Deformable Part Model)算法中模型可视化的解释

DPM源码(voc-release)中的模型可视化做的还算相当炫酷的,可以让我们直观的看到训练好的模型,甚至我们不用去做模型的评价,直接根据肉眼的观察,就能大致了解一个目标训练的好不好,比如我训练一个人体模型,那他的可视化图当然就是越接近人体越好. 下面是对DPM源码中有关模型可视化部分代码的分析,通过分析这些代码,有助于更好的理解DPM模型. 注意:我的源码版本是voc-release3.1,第4版往后的模型变得更复杂,这里不讨论. 有关模型可视化的代码主要在visualizemodel.m,

深入理解JDK中的I/O

深入理解JDK中的I/O 目 录 java内存模型GCHTTP协议事务隔离级并发多线程设计模式清楚redis.memcache并且知道区别mysql分表分库有接口幂等性了解jdk8稍微了解一下特性 jvm内存模型:堆和非堆,http://www.cnblogs.com/RunForLove/p/4775999.html  对这部分的理解,只集中在关乎我们编程的东西部分. 堆就是Java代码可及的内存,是留给开发人员使用的:非堆就是JVM留给自己用的.堆.非堆:虚拟机栈.本地方法栈.程序计数器.方

理解RabbitMQ中的AMQP-0-9-1模型

前提 之前有个打算在学习RabbitMQ之前,把AMQP详细阅读一次,挑出里面的重点内容.后来找了下RabbitMQ的官方文档,发现了有一篇文档专门介绍了RabbitMQ中实现的AMQP模型部分,于是直接基于此文档和个人理解写下这篇文章. AMQP协议 AMQP全称是Advanced Message Queuing Protocol,它是一个(分布式)消息传递协议,使用和符合此协议的客户端能够基于使用和符合此协议的消息传递中间件代理(Broker,也就是经纪人,个人感觉叫代理合口一些)进行通信.

深入理解CSS中的层叠上下文和层叠顺序(转)

by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在CSS届,也是如此.只是,一般情况下,大家歌舞升平,看不出什么差异,即所谓的众生平等.但是,当发生冲突发生纠葛的时

关于C语言中的强符号、弱符号、强引用和弱引用的一些陋见,欢迎指正

首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引用.在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样感觉的朋友交流也希望高人指点. 首先我们看一下书中关于它们的定义. 引入场景:(1)文件A中定义并初始化变量i(int i = 1), 文件B中定义并初始化变量i(int i = 2).编译链接A.B时会报错b.o:(.data+0x0): multiple definition of `i':a.o:(.d

c/c++中#和##链接符号的用法

#include <stdio.h> #include <stdlib.h> /* 英语原文: In function-like macros, a # operator before an identifier in the replacement-list runs the identifier through parameter replacement and encloses the result in quotes, effectively creating a stri