python04--算法的代价及其度量(P14)

1.把算法的代价看作规模的函数之后,很容易看到一种必然出现的情况:

   可能有一些算法,随着实例规模的增长,其时间(或空间)开销的增长非常快,

   而另一些算法的开销函数随着规模增长而增长的比较慢,

这两个函数关系称为算法的时间代价和空间代价。

2.人们主要关注算法的最坏情况代价,有时也关注算法的平均代价,而算法的最乐观的估计基本上没有价值。

3.对于算法的时间和空间性质,最重要的是其量级和趋势,这些是代价的主要部分。

  例如:可以认为3n²和100n²属于同一个量级

4.”大O记法“

  假设存在函数g,使得算法A处理规模为n的问题实例所用的时间T(n)=O(g(n)),则称O(g(n))为算法A的渐进时间复杂度,简称时间复杂度

  算法的空间复杂度S(n)的定义与此类似。S(n)=O(g(n) )

  最常用的渐进复杂度函数:

    O(1),O(log n),O(n),O(n log n),O(n²),O(n³),O(2n)

5.基本循环程序

  这里只考虑算法的时间复杂度,基本循环程序只有顺序组合,条件分支和循环结构。

  分析算法的几条基本计算规则:

  0.基本操作,认为其时间复杂度为O(1)。如果是函数调用,应该将其时间复杂度代入,参与整体时间复杂度的计算。

  (1)加法规则(顺序组合)。如果算法(或所考虑算法片段)是两个部分(或多个部分)的顺序组合,其复杂性是这两部分(或多部分)的复杂性之和。以两个部分为例:

        T(n) = T1(n)+T2(n) = O(T1(n))+O(T2(n)) = O(max(T1(n),T2(n)))

  其中T1(n)和T2(n)分别为顺序组合的两个部分的时间复杂度。由于忽略了常量因子,加法等价于求最大值,取T1(n)和T2(n)中复杂度较高的一个。

  (2)乘法规则(循环结构)。如果算法(或所考虑的算法片段)是一个循环,循环体将执行T1(n)次,每次执行需要T2(n)时间,那么:

        T(n) = T1(n) * T2(n) = O(T1(n))*O(T2(n)) = O(T1(n) * T2(n))

  (3)取最大规则(分支结构)。如果算法(或所考虑算法片段)是条件分支,两个分支的时间复杂性分别为T1(n)和T2(n),则有:

        T(n) = O(max(T1(n),T2(n)))

几个例子:

for i in range(n):
    for j in range(n):
        x = 0.0
        for k in range(n):
            x = x + m1[i][k] * m2[k][j]
        m[i][j] = x
时间复杂度为:
  T(n) = O(n)*O(n)*(O(1)+O(n)*O(1)+O(1))
     = O(n)*O(n)*O(n)
     = O(n*n*n)
     = O(n³)
data=[]
while 还有数据:
    x = 下一数据
    data.insert(0,x)    # 表新数据加到表的最前面
时间复杂度为:
  T(n) = O(1)+O(n)*(O(1)+O(n))
     = O(n²)
data=[]
while 还有数据:
    x = 下一数据
    data.insert(len(data),x)    # 表新数据加到表的最后面,或写data.append(x)
时间复杂度为:
  T(n) = O(1)+O(n)*(O(1)+O(1))
     = O(n)

6.时间开销

  • 构造新结构,如构造新的list、set等。

       构造新的空结构(空表、空集合等)是常量时间操作,

       而构造一个包含n个元素的结构,则至少需要O(n)时间。

  • 一些list操作的效率:

       表元素访问和元素修改是常量时间操作,

       但一般的加入、删除元素操作(即使只加入一个元素)都是O(n)时间操作。

  • 字典dict操作的效率:

       主要操作是加入新的关键码-值对和基于关键码查找关联值。

       它们的最坏情况复杂度是O(n),但平均复杂度是O(1)。

       也就是说,一般而言字典操作的效率很高,但偶尔也会出现效率低的情况。

   空间开销

  • 在程序里使用任何类型的对象,都需要付出空间的代价。建立一个表或者元组,至少要占用元素个数那么多空间,即O(n)的存储空间,如果元素也是新创建的,还需要考虑元素本身的存储开销。
  • 集合和字典需要支持快速查询等操作,其结构更加复杂。包含n个元素的集合或字典,至少需要占用O(n)的存储空间。

  【注意】

     python中的各种组合数据对象都没有预设的最大元素个数。在实际使用中,这些结构能根据元素个数的增长自动扩充存储空间。从空间占用的角度看,其实际开销在存续期间可能变大,但通常不会自动缩小(即使后来元素变得很少了)。举个例子,假设程序里建了个表,而后不断加入元素导致表变得很大,而后又不断删除元素,后来表中元素变得很少,但占用的存储空间并不减少。

      还应该注意pyhton自动存储管理系统的影响。举个例子:如果在程序里建立了一个表,此后一直将其作为某个全局变量的值,这个对象就会始终存在并占用空间。如果将其作为函数里局部变量的值,或者虽然作为全局变量的值,但后来通过赋值将其抛弃,这个表对象就可以被回收。

原文地址:https://www.cnblogs.com/yanyufeng/p/9619907.html