算法时间复杂度lg是多少_时间复杂度入门理解

前言

当你编写完一个程序的时候,怎样对它进行算法最优的判断呢?效率又是怎样体现的呢?效率=总执行次数/总时间,一般来说,程序越庞大,其执行效率越低。因此,对于模块化程序,优化其算法的时间复杂度是非常重要的。

定义

我们把一个算法中的语句执行次数定义为频度,算法的运行时间刻画为一个函数,定义为 T(n) ,其中n称为问题的规模,当n不断变化时,T(n)也随之变化。但我们想知道n与T(n)之间的大致规律,所以我们引入渐进符号 O 来刻画算法的运行时间。

现在我们编写一个程序,把其中表示算法运行时间的函数记为 T(n)。对于一个给定的函数 g(n),有 O(g(n)) = {f(n) | 存在常量 c, n0, c>0, n0>0, 使得对所有 n ≥ n0, 有0  ≤ f(n)  ≤ c·g(n)},记作 f(n) = O(g(n)) 。如下图。注意这个等号并不是左右相等,而是代表集合论中的 “∈”,表示 'is a ..' 的关系,如“ n = O(n2) ”。当我们说运行时间为 O(g(n)) 时,表示存在一个O(g(n)) 的函数 f(n),使得 n 不管输入什么值时,T(n) 的上界都是 f(n)。所以 O(g(n)) 表示最坏情况运行时间。

通常,我们称 O(g(n)) 为时间复杂度。

图(a) f(n) = O(g(n))

按增长量级递增排列,常见的时间复杂度有:

常数阶O(1), 对数阶O(log2n), 线性阶O(n), 线性对数阶O(nlog2n), 平方阶O(n^2), 立方阶O(n^3),..., k次方阶O(n^k), 指数阶O(2^n) 。

计算时间复杂度

粗略地计算的话就知道以下三步即可:

1.去掉运行时间中的所有加法常数。

2.只保留最高阶项。

3.如果最高阶项存在且不是1,去掉与这个最高阶相乘的常数得到时间复杂度

我们看一个例子

for (int i = 0; i < n; i++) {

for (int j = i; j < n; j++) {

// do .....

}

}

当 i = 0 时 里面的for循环执行了n次,当i等待1时里面的for循环执行了n -  1次,当i 等于2里里面的fro执行了n - 2次........这样,就可以将循环对应成等差数列,项数为最外层循环的次数,公差为1,首项是i = 0  or  i = n-1 时内层循环的执行次数,末项是i = n-1  or  i = 0 时的内层循环的执行次数所以执行的次数是

那么得到运行时间的函数

  (c 是常数)

根据我们上边的时间复杂度算法

1.去掉运行时间中的所有加法常数: 没有加法常数不用考虑

2.只保留最高阶项: 只保留

3. 去掉与这个最高阶相乘的常数:  去掉

只剩下 

最终这个算法的时间复杂度为

下面拿几道题练练手:

(1)

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

s++;//循环了n*n次,当然是O(n^2)

(2)

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

s++;//循环了(n+n-1+n-2+...+1)≈(n^2)/2,因为时间复杂度是不考虑系数的,所以也是O(n^2)

(3)

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

s++;//循环了(1+2+3+...+n)≈(n^2)/2,当然也是O(n^2)

(4)

i=1;k=0;while(i<=n-1){

k+=10*i;

i++;

}//循环了n-1≈n次,所以是O(n)

(5)

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

x=x+1;//循环了(1^2+2^2+3^2+...+n^2)=n(n+1)(2n+1)/6(这个公式要记住哦)≈(n^3)/3,不考虑系数,自然是O(n^3)

需要注意的是,在时间复杂度中,log(2,n)(以2为底)与lg(n)(以10为底)是等价的,因为对数换底公式:

log(a,b)=log(c,b)/log(c,a)

所以,log(2,n)=lgn/lg2,忽略掉系数,二者当然是等价的

在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1),譬如简单的求和,代码如下,其频度为3,O(1)

inta,b; //频度为2

printf("%d",a+b); //频度为1return 0;

实践出真知,下面放一些更难的例题,帮助理解与计算时间复杂度

例一:下面是求50以内的奇数和的代码,求时间复杂度

(例 1.1)

(例 1.2)

注意:其中的 floor() 和 ceil() 分别是向下取整和向上取整

例二:

while(n!=0)

{

n/=10;

}

时间复杂度是O(lgn)

解析:设规模为n,运行时间为T(n)。

若n有五位数,则语句执行五次。

设变量N==位数,则有当n有N位数时,语句执行N次。得N^10=n.

则lgn=N。此时运行时间与问题规模的关系为 T(n) = c*N = c*lgn (c是常数)

所以时间复杂度为 O(lgn)

例三:

while(n!=0)

{

n=n/2;

}

时间复杂度O(lgn)

解析:

设n=2^m,则循环执行了m+1次,m=1+log2n=1 + lg(n)/lg(2),因此频度为 1+lg(n)/lg(2),运行时间 T(n) = 1 + lg(n) / lg(2)

时间复杂度为 O(lgn)

例四:

void func(int n)

{

int i=0,s=0;

while(s

{

i++;

s=s+i;

}

}

时间复杂度O(n^(1/2))

解析:

测试样例: n = 3,5,9,...n^2 ,可得频度 N = 2,3,4,...n^(1/2) (近似计算)

则运行时间 T(n) = c*(n^(1/2)) + c2 (c, c2为常数),可得时间复杂度 O(n^(1/2))

例五:

x=91; y=100;while(y>0)

{if(x>100)

{

x=x-10;

y--;

}else x++;

}

这题易错当为线性阶O(n),我自己就犯了循环就是常数阶的错误,其实这是常数阶O(1)

常见算法的时间复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值