Python中的数据结构和面向对象设计模式的算法

第2章                             算法分析

什么是算法,我们为什么要对算法进行分析呢?算法就是实现某些目的所需要的一步一步的步骤(程序)。一种算法的可以有多重描述方式,例如它可以用英语来写,或者法语,亦或是其他任何的自然语言。然而在这我们所关注的算法特指的是使用合适的数学形式体系来描述的,如编程语言。

如果给我一个算法的表达式,我们能用它来做什么呢?很明显我们可以运行这个程序,观察它的行为。在一般情况下,这样做似乎也没有什么好处。如果我们在特定的计算机上运行特定的程序,给予其特定的一组输入,然后可以知道的是单一实例下该程序的行为。这样的知识是轶闻的,而我们在基于轶事证据下结论的时候也需要格外小心。

为了更多的了解一个算法,我们可以对它进行分析。通过这样的方法,我们可以详细的了解算法,对算法的具体实现和程序性能得出一般的结论。我们能做哪些分析呢?

l        确定程序在不同输入情况下的运行时间的函数

l        确定程序运行所需的总的内存空间或最大内存空间

l        确定程序代码的总容量

l        确定程序是否正确的计算出所想要的结果

l        确定程序的复杂度,例如程序是否易于阅读,理解,修改等等

l        确定程序的鲁棒性,例如程序是否能对意料之外的或者错误的输入进行处理

在本书中,我们主要关心的是程序的运行时间。我们也会考虑运行程序所需的内存空间。能够影响程序的运行时间的因素有很多,其中有算法本身,输入数据和我们运行程序的计算机系统等。计算机的性能是由以下因素决定的:

l        硬件:1、所用的处理器(类型和速度)2、可用的内存大小(高速缓存和随机访问内存)3、可用的硬盘容量

l        实现算法所用的编程语言

l        编程语言的编译器或解释器

l        计算机的操作系统

如果要考虑以上所有因素来对程序的性能进行具体分析的话,这将是一项非常艰巨且耗时的任务。更进一步来说,这样的分析也并没有多大的实际意义。这是因为由于现代底层科技的高速发展,我们这样分析得出的结论未必在新一代的硬件和软件上同样适用。

为了克服这个缺点,我们设计出了计算机的动作模型在简化我们的分析过程的同时使我们的分析仍能得出有意义的结论。接下来的部分将会介绍一系列的这样的模型。

 

2.1          计算机的详细模型

   在这一部分中,我们建立了Python程序运行时间的一个详细模型。该模型并不依赖于底层的硬件和系统软件。在这个模型中,我们选择的Python程序的运行是基于Python虚拟机(如下图所示),而不是去分析在某个特定选择的物理机上程序的性能。

 

                                               

图:Python系统概览

    这样做的直接后果是我们将失去一定的精确度,结论模型并不能准确预测所有可能硬件或软件系统上程序的性能。另一方面,结论模型在细节上仍然非常复杂。

2.1.1  基本公理

通用语言的运行时间性能是由以下我们假定的一组公理来描述的。

 

第一个公理讲的是命名操作的运行时间:

 

公理:从内存中获取一个命名对象需要的时间是一个常数Tfetch,给一个对象捆绑一个新的名字,并存储到内存中需要的时间也是一个常数Tstore.

根据上面的公理,赋值语句y=x的运行时间就是Tfetch+Tstore,即获取名字为x的对象所需要的时间就是Tfetch,然后将名字y与这个对象连接并存储到内存的时间是Tstore。这个公理在常数的情况下仍然适用:赋值语句y=1的运行时间仍然是Tfetch+Tstore。为什么会是这样的呢?我们可以将常数1视为值为1的整数对象。因此,我们获取对象名为1的对象的开销和获取其他对象的开销是一样的。

 

下面这个公理讲的是算数运算的运行时间:

 

公理:基本的算数运算,如加法、减法、乘法、除法和比较,所需要的时间都是常数。它们所需要的时间各自用T+,T-,Yx,T÷,和T<来表示。

 

根据上面的公理,所有上面的简单运算操作都可以在固定的常数时间内完成。要使上面的结论成立,则要求表示数值的比特位数也是固定的。在Python中,(a plain integer )整型数可以用32位比特来表示。只要操作数和操作的结果都是整型数,我们就可以说该操作的运行时间是固定的。Python同时也支持长整型,长整数可以拥有不定长的位数(只要有足够的内存)。如果使用了长整型,那么该基本数学运算的运行时间也不确定,上面的公理不再适用。

 

综合运用上面的两个公理的,我们可以得出语句y=y+1的运行时2Tfetch + T+ + Tstore.这是因为,在这个过程中,我们需要分别获取命名为y和1的对象,将他们求和并创建一个新的值为该和的对象,然后将命名y和这个对象连接并存储到内存中。

 

Python的语法对这样的计算提供了另一种表达方式:y+=1.我们可以假设这样的表达式所需的运行时间和原来的语句是一样的。

 

第三个公理表述的是调用(call)和返回(return)的运行时间:

 

公理:调用(call)方法(method)所需要的时间是一个常数Tcall,方法返回需要的时间也是一个常数Treturn。

 

 

 

 


转载于:https://my.oschina.net/u/2440318/blog/618024

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值