转--算法时间复杂度

算法的时间复杂度定义为:算法

在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化状况并肯定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记做:T(n}=0(f(n))。它表示随问题规模n的增大,算法执行时间的埔长率和 f(n)的埔长率相同,称做算法的渐近时间复杂度,简称为时间复杂度。其中f( n)是问题规横n的某个函数。数据结构

这样用大写O()来体现算法时间复杂度的记法,咱们称之为大O记法。通常状况下,随着n的增大,T(n)增加最慢的算法为最优算法。
以前咱们说的三个求和算法的时间复杂度分别为0(n),0(1),0(n2)。我就推一下吧。
计算 1 + 2 + 3 + 4 + ...... + 100。代码以下,以前也有讲过:函数

include "stdio.h"

int main()
{
int i, sum = 0, n = 100; /* 执行1次 /
for( i = 1; i <= n; i++) /
执行 n+1 次 /
{
sum = sum + i; /
执行n次 /
//printf("%d \n", sum);
}
printf("%d", sum); /
执行1次 */
}
从代码附加的注释能够看到全部代码都执行了多少次。那么这写代码语句执行次数的总和就能够理解为是该算法计算出结果所须要的时间。该算法所用的时间(算法语句执行的总次数)为: 1 + ( n + 1 ) + n + 1 = 2n + 3性能

而当 n 不断增大,好比咱们此次所要计算的不是 1 + 2 + 3 + 4 + ...... + 100 = ? 而是 1 + 2 + 3 + 4 + ...... + n = ?其中 n 是一个十分大的数字,那么因而可知,上述算法的执行总次数(所需时间)会随着 n 的增大而增长,可是在 for 循环之外的语句并不受 n 的规模影响(永远都只执行一次)。因此咱们能够将上述算法的执行总次数简单的记作: 2n 或者简记 n设计

这样咱们就获得了咱们设计的算法的时间复杂度,咱们把它记做: O(n)code

再来看看高斯的算法:io

include "stdio.h"

int main()
{
int sum = 0, n = 100; /* 执行1次 /
sum = (1 + n)
n/2; /* 执行1次 */性能分析

printf("%d", sum);      /* 执行1次 */

}
这个算法的时间复杂度: O(3),但通常记做 O(1)。效率

从感官上咱们就不难看出,从算法的效率上看,O(3) < O(n) 的,因此高斯的算法更快,更优秀。数据结构与算法

下面再来一个例子:

include "stdio.h"

int main()
{
int i, j, x = 0, sum = 0, n = 100; /* 执行1次 /
for( i = 1; i <= n; i++)
{
sum = sum + i;
//printf("%d \n", sum);
for( j = 1; j <= n; j++)
{
x++; /
执行nn次 /
sum = sum + x;
}
}
printf("%d", sum); /* 执行1次 */
}
上面的代码严格的说不能称之为一个算法,毕竟它很“无聊并且莫名其妙”(毕竟算法是为了解决问题而设计的嘛),先不论这个“算法”能解决什么问题,咱们看一下它的“大O阶”如何推导,仍是先计算一下它的执行总次数:

执行总次数 = 1 + (n + 1) + n(n + 1) + nn + (n + 1) + 1 = 2n2 + 3n + 3

如何推导大o阶呢?咱们给出了下面 的推导方法:

用常数1取代运行时间中的全部加法常数。
在修改后的运行次数函数中,只保留最髙阶项。
若是最高阶项存在且不是1,则去除与这个项相乘的常数。
按照上面推导“大O阶”的步骤咱们先来第一步:“用常数 1 取代运行时间中的全部加法常数”,则上面的算式变为:执行总次数 = 2n^2 + 3n + 1

第二步:“在修改后的运行次数函数中,只保留最高阶项”。这里的最高阶是 n 的二次方,因此算式变为:执行总次数 = 2n^2

第三步:“若是最高阶项存在且不是 1 ,则去除与这个项相乘的常数”。这里 n 的二次方不是 1 因此要去除这个项的相乘常数,算式变为:执行总次数 = n^2

所以最后咱们获得上面那段代码的算法时间复杂度表示为: O( n^2 )

最后咱们在把常见的算法时间复杂度以及他们在效率上的高低顺序记录在这里,是你们对算法的效率有个直观的认识。
O(1) 常数阶 < O(logn) 对数阶 < O(n) 线性阶 < O(nlogn) < O(n^2) 平方阶 < O(n^3) < { O(2^n) < O(n!) < O(n^n) }

最后三项用大括号把他们括起来是想要告诉你们,若是往后你们设计的算法推导出的“大O阶”是大括号中的这几位,那么趁早放弃这个算法,在去研究新的算法出来吧。由于大括号中的这几位即使是在 n 的规模比较小的状况下仍然要耗费大量的时间,算法的时间复杂度大的离谱,基本上就是“不可用状态”。
延伸阅读
此文章所在专题列表以下:

第一话:你的数据结构怎么学的? 第二话:数据结构的历史与来由 第三话:关于数据结构的一些概念 第四话:数据的逻辑结构 第五话:数据的物理结构 第六话:关于数据类型 第七话:抽象数据类型ADT 第八话:补充数据结构基本概念的关系 第九话:数据结构与算法的关系 第10话:什么是算法? 第11话:算法的五个基本特征 第12话:什么样的算法才是好算法 第13话:算法的性能分析 第14话:如何计算算法的时间复杂度 第15话:算法的最坏状况与平均状况 第16话:算法的空间复杂度

相关文章
相关标签/搜索