算法时间复杂度的渐近表示法

基础知识点

一个算法的时间复杂度,指算法运行的时间。

假设数据输入规模是n,算法的复杂度可以表示为f(n)的函数

接受上界不接受下界

大O记号(不唯一)(一般找最邻近它的那个)

假设f(n)和g(n)的定义域是非负整数,存在两个正整数c和n0,使得n>n0的时候,f(n)≤c*g(n),则f(n)=O(g(n))。可见O(g(n))可以表示算法运行时间的上界。O(g(n))表示的函数集合的函数是阶数不超过g(n)的函数。

例如:f(n)=2*n+2=O(n)

证明:当n>3的时候,2*n +2<3n,所以可选n0=3,c=3,则n>n0的时候,f(n)<c*(n),所以f(n)=O(n)。

现在再证明f(n)=2*n+2=O(n^2)

证明:当n>2的时候,2*n+2<2*n^2,所以可选n0=2,c=2,则n>n0的时候,f(n)<c*(n^2),所以f(n)=O(n^2)。

同理可证f(n)=O(n^a),a>1

Ω记号(第二十四个希腊字母欧米伽大写Ω,小写ω)(不唯一)

Ω记号与大O记号相反,他可以表示算法运行时间的下界。Ω(g(n))表示的函数集合的函数是所有阶数超过g(n)的函数。

例如:f(n)=2*n^2+3*n+2=Ω(n^2)

证明:当n>4的时候,2*n^2+3*n+2>n^2,所以可选n0=4,c=1,则n>n0的时候,f(n)>c*(n^2),所以f(n)=Ω(n^2)。

同理可证f(n)=Ω(n),f(n)=Ω(1)

Θ记号(读法:sei ta)

小o记号

f(n)=o(g(n))当且仅当f(n)=O(g(n))且f(n)≠Ω(g(n))。也就是说小o记号可以表示时间复杂度的上界,但是一定不等于下界。

常见的时间复杂度介绍

常见的时间复杂度如下表所示

执行次数函数非正式术语
12O(1)常数阶
2n+3O(n)线性阶
3n²+2n+1O(n²)平方阶
5logn+20O(logn)(以2为底数)对数阶
2n+3nlogn+19O(nlogn)nlogn阶
6n³+2n²+3n+4O(n³)立方阶
2ⁿO(2ⁿ)指数阶


常用的时间复杂度所耗费的时间从大到小依次是:

              O(1) < O(logn) <O(n) < O(nlogn) < O(n²) < O(n³) < O(2ⁿ) < O(n!) <O(nⁿ)

我们前面以及谈到了O(1)常数阶、O(logn)对数阶、O(n)线性阶、O(n²)平方阶等,至于O(nlogn)等都类似分析,而像O(n³),过大的n都会使得结果变得不现实。同样指数阶O(2ⁿ)和阶乘阶O(n!)等除非是很小的n值,否则哪怕n只是100,都是噩梦般的运行时间。

推导大O阶方法

  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则去除与这个项相乘的常数。得到的结果就是大O阶

 常数阶 

int sum = 0, n = 100;  /*执行一次*/
sum = (1+n)*n/2; /*执行一次*/
printf("%d",sum); /*执行一次*/
  • 这个算法的运行次数函数是f(n)=3。根据我们推导大O阶的方法,第一步就是把常数项3改为1。在保留最高阶项时发现,它根本没有最高阶项,所以这个算法的时间复杂度为O(1)。
  • 我们又可以试想一下,如果这个算法当中的语句sum=(1+n)*n/2 有10句。事实上无论n为多少,这两段代码就是3次和12次执行的差异。这种与问题的大小无关(n的多少),执行时间恒定的算法,我们称之为具有O(1)的时间复杂度,又叫常数阶。
  • 注意:不管这个常数是多少,我们都记作O(1),而不能是O(3)、O(12)等其他融合数字,这是初学者常常犯的错误。

线性阶

int i;
for(i = 0; i < n; i++)
{ 
   /*时间复杂度为O(1)的程序步骤序列 */
}
  • 它的循环的时间复杂度为O(n),因为循环体中的代码需要执行C*n次。(C为任意常数)

 对数阶

int count = 1;
while( count < n )
{
	count = count * 2;#对数阶的关键语句
	/* 时间复杂度为O(1)的程序步骤序列 */
}
  • 由于每次count乘以2之后,就距离n更近了一分。也就是说,有多少个2相乘后大于n,则会退出循环。由2^x= n 得到 x = logn 。所以这个循环的时间复杂度为 O(logn)。

平方阶

int i , j;
for( i = 0; i < n; i++)
{
	for(j = 0; j<n; j++)
	{
		/* 时间复杂度为O(1)的程序步骤序列 */
	}
}
  • 它的内循环刚才我们已经分析过,时间复杂度为O(n)。 而对于外层的循环,不过是内部这个时间复杂度为O(n)的语句,再循环n次。所以这段代码的时间复杂度为O(n²)

如果外循环的循环次数改为了m,时间复杂度就变为O(m X n)

int i,j;
for(i= 0; i < m; i++)
{
	for(j = 0; j < n; j++)
	{
		/* 时间复杂度为O(1)的程序步骤序列 */
	}
}
  •  循环的时间复杂度等于循环体的复杂度乘以该循环运行的次数

这个嵌套的辅助度等于多少了,注意内层循环的起始条件

int i,j;
for(i = 0; i < n; i++)
{
	for(j = i; j < n; j++) /* 注意 j = i 而不是0 */
	{
		/* 时间复杂度为O(1)的程序步骤序列 */
	}
}

由于当i = 0 时,内循环执行了n次,当i=1时,执行了n-1次,…当i = n-1时,执行了1次。所以总的执行次数为: 

 

 

 

  • 用我们推导大O阶的方法,第一条,没有加法常数不予考虑;第二条,只保留最高阶项,因此保留n^2/2;第三条,去除这个项相乘的常数,也就是去除1/2,最终这段代码的时间复杂度为O(n²)。

文章参考:

(26条消息) 算法时间复杂度推导大O阶方法_栗子君blog的博客-CSDN博客_大o阶算法s

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值