1.2 算法分析:

Untitled.png

分为:事后统计法与事前分析估算法。

当然,第一种需要执行程序。而且存在着其他的因素来干扰结果。(与硬件有关)

所以采用事前分析评估法来分析算法的效率。

1.2.1算法时间复杂度分析:

算法是由控制结构(顺序,分支,循环3种)和原操作(固有数据类型的操作)构成。

算法的的运行时间取决于两者的综合效果。o

Untitled 1.png

设n为算法中的问题规模,通常用大O、大Ω或 等三种渐进符号表示算法的执行时间与n之间的一种增长关系。

Untitled 2.png

算法的执行时间主要与问题规模有关(即数据的多少有关)不妨将数据规模设为n;

分析问题规模n,找出基本语句,求出其运行次数f(n)。

基本语句:算法中的基本语句是执行次数与整个算法的执行次数程正比的语句,他对算法执行时间的贡献最大(最费时间),是算法中最重要的操作。(上文的例子中:s+=a[i][i]便是基本语句。)

在此例子中:f(n)=n

这种时间衡量方法得出的不是具体的时间,而是一种增长趋势的度量(即加速度)。换而言之,这是在n足够大的情况下算法中基本语句的执行次数在渐进意义下的(我们可以将其理解为高阶,低阶这样的概念)

大o表示法:

大O表示法就是将算法的所有步骤转换为代数项,然后排除不会对问题的整体复杂度产生较大影响的较低阶常数和系数。

数学家可能会对我的“整体影响”假设有点沮丧,但是开发人员为了节省时间,这种方式更容易简化问题:

规律 Big-O 2 O(1) --> 就是一个常数 2n + 10 O(n) --> n 对整体结果会产生最大影响 5n^2 O(n^2) --> n^2 具有最大影响

简而言之,这个例子所要表达的就是:我们只关注表达式中对表达式最终结果会产生最大影响的因子。(当常数非常大而n很小的时候并不是这样的,但是我们现在不要担心这种情况)。

下面是一些常用的时间复杂度以及简单的定义。更完整的定义可以翻阅维基百科(英文)。

  • O(1)— 常量时间:给定一个大小为n的输入,概算法只需要一步就可以完成任务。
  • O(log n)—对数时间:给定大小为n的输入,该算法每执行一步,它完成任务所需要的步骤数目会以一定的因子减少。
  • O(n)—线性时间:给定大小为n的输入,该算法完成任务所需要的步骤直接和n相关(1对1的关系)。
  • O(n²)—二次方时间:给定大小为n的输入,完成任务所需要的步骤是n的平方。
  • O(C^n)—指数时间:给定大小为n的输入,完成任务所需要的步骤是一个常数的n次方(非常大的数字)。(c为常数)

Untitled 3.png

从图中我们也可以看到不同的效率对于事件的影响是极大的。

在这个网站中我们也可以看到一些常见的算法效率:

Know Thy Complexities!

那么?什么才是大o表示法:下面的链接讲述的很详细。

Analysis of Algorithms | Big-O analysis - GeeksforGeeks

综合来讲,大o表示法表示的是增长率的上界。

而且需要的是紧凑上界!!!

1 2.jpeg

大Ω表示法:

大Ω符号用来描述增长率的下界,表示f(n)的增长最少像g(n) 增长的那样快,也就是说,

当输入规模为n时,算法消耗时间的最小值。 与大O符号对称,这个下界的阶越高,结果就越有价值,所以,对于10n~2+4n+2,Ω(n2)比Ω(n) 有价值。一个算法的时间用大Ω符号表示时,总是采用最有价值的g(n)表示,称之为“紧凑下界”或“紧确下界”。

大 表示法:

大?符号比大O符号和大Ω符号都精确,

当且仅当g(n)既是f(n)的上界又是f(n)的下界。即当大o表示法和大Ω表示法相同时,即为该表示法。

最后:如下:分别表示3种符号

Untitled 4.png

另附以下特性:

1 2 1.jpeg

额。

⑴ 找出算法中的基本语句; 算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。 ⑵ 计算基本语句的执行次数的数量级; 只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。 ⑶ 用大Ο记号表示算法的时间性能。 将基本语句执行次数的数量级放入大Ο记号中。 如果算法中包含嵌套的循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加。例如:

for (i=1; i<=n; i++)       x++;  for (i=1; i<=n; i++)       for (j=1; j<=n; j++)            x++;

第一个for循环的时间复杂度为Ο(n),第二个for循环的时间复杂度为Ο(n2),则整个算法的时间复杂度为Ο(n+n2)=Ο(n2)。 Ο(1)表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,其时间复杂度就是Ο(1)。其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)称为多项式时间,而Ο(2n )和Ο(n!)称为指数时间。计算机科学家普遍认为前者(即多项式时间复杂度的算法)是有效算法,把这类问题称为P(Polynomial,多项式)类问题,而把后者(即指数时间复杂度的算法)称为NP(Non-Deterministic Polynomial, 非确定多项式)问题。 一般来说多项式级的复杂度是可以接受的,很多问题都有多项式级的解——也就是说,这样的问题,对于一个规模是n的输入,在n^k的时间内得到结果,称为P问题。有些问题要复杂些,没有多项式时间的解,但是可以在多项式时间里验证某个猜测是不是正确。比如问4294967297是不是质数?如果要直接入手的话,那么要把小于4294967297的平方根的所有素数都拿出来,看看能不能整除。还好欧拉告诉我们,这个数等于641和6700417的乘积,不是素数,很好验证的,顺便麻烦转告费马他的猜想不成立。大数分解、Hamilton回路之类的问题,都是可以多项式时间内验证一个“解”是否正确,这类问题叫做NP问题。

(4)在计算算法时间复杂度时有以下几个简单的程序分析法则:

(1).对于一些简单的输入输出语句或赋值语句,近似认为需要O(1)时间

(2).对于顺序结构,需要依次执行一系列语句所用的时间可采用大O下”求和法则” 求和法则:是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1(n)+T2(n)=O(max(f(n), g(n))) 特别地,若T1(m)=O(f(m)), T2(n)=O(g(n)),则 T1(m)+T2(n)=O(f(m) + g(n))

(3).对于选择结构,如if语句,它的主要时间耗费是在执行then字句或else字句所用的时间,需注意的是检验条件也需要O(1)时间

(4).对于循环结构,循环语句的运行时间主要体现在多次迭代中执行循环体以及检验循环条件的时间耗费,一般可用大O下”乘法法则” 乘法法则: 是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1T2=O(f(n)g(n))

(5).对于复杂的算法,可以将它分成几个容易估算的部分,然后利用求和法则和乘法法则技术整个算法的时间复杂度 另外还有以下2个运算法则:(1) 若g(n)=O(f(n)),则O(f(n))+ O(g(n))= O(f(n));(2) O(Cf(n)) = O(f(n)),其中C是一个正常数

(5)下面分别对几个常见的时间复杂度进行示例说明:

(1)、O(1)

Temp=i; i=j; j=temp;

以上三条单个语句的频度均为1,该程序段的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为常数阶,记作T(n)=O(1)。注意:如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

(2)、O(n2)** 2.1. 交换i和j的内容

sum=0;                 (一次)  
for(i=1;i<=n;i++)     (n+1次)   
for(j=1;j<=n;j++) (n2次)      
sum++;            (n2次)

解:因为Θ(2n2 +n+1)=n2 (Θ即:去低阶项,去掉常数项,去掉高阶项的常参得到),所以T(n)= =O(n2);

2.2.

for (i=1;i<n;i++)   {    y=y+1;         ①      
for (j=0;j<=(2*n);j++)          x++;         ②    }

解: 语句1的频度是n-1 语句2的频度是(n-1)(2n+1)=2**n2 -n-1 f(n)=2n2 -n-1+(n-1)=2n2 -2; 又Θ(2n2-2)=n2 该程序的时间复杂度T(n)=O(n2 ). 一般情况下,对步进循环语句只需考虑循环体中语句的执行次数,忽略该语句中步长加1、终值判别、控制转移等成分,当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。 (3)、O(n)*

a=0;  b=1;                      ①  
for (i=1;i<=n;i++) ②  {     
s=a+b;    ③   
b=a;     ④     
a=s;     ⑤  }

解: 语句1的频度:2, 语句2的频度: n, 语句3的频度: n-1, 语句4的频度:n-1, 语句5的频度:n-1, T(n)=2+n+3(n-1)=4n-1=O(n).

(4)、O(log2n)

i=1;     ①  
hile (i<=n)  i=i*2; ②

解: 语句1的频度是1, 设语句2的频度是f(n), 则:2^f(n)<=n;f(n)<=log2n 取最大值f(n)=log2n, T(n)=O(log2n )

(5)、O(n3)

for(i=0;i<n;i++)   {      
for(j=0;j<i;j++)      {       
for(k=0;k<j;k++)          
x=x+2;      }   }

解:当i=m, j=k的时候,内层循环的次数为k当i=m时, j 可以取 0,1,…,m-1 , 所以这里最内循环共进行了0+1+…+m-1=(m-1)m/2次所以,i从0取到n, 则循环共进行了: 0+(1-1)1/2+…+(n-1)n/2=n(n+1)(n-1)/6所以时间复杂度为O(**n3)*