|
|
|
|
移动端

1.12.1 函数调用(2)

《程序员面试笔试真题与解析》本书针对当前各大 IT企业面试笔试中特性与侧重点,精心挑选了 3年以来近百家典型 IT企业的面试笔试真题,这些企业涉及业务包括系统软件、搜索引擎、电子商务、手机 APP、安全关键软件等,面试笔试真题非常具有代表性与参考性。本节为大家介绍函数调用。

作者:猿媛之家来源:机械工业出版社|2017-12-06 17:24

开发者盛宴来袭!7月28日51CTO首届开发者大赛决赛带来技术创新分享

1.12.1 函数调用(2)

【真题 171】有如下代码:

  1. int foo(int n)  
  2. {  
  3. if (n <= 1)  
  4. return 1;  
  5. return n*foo(n - 1);  

上述代码的时间复杂度为()。

A.O(log2n) B.O(n) C.O(nlog2n)  D.O(n^2) 答案:B。函数 foo递归次数只与 n有关。这道题实际上是用来求 n的阶乘的,递归次数为 n,因此,时间复

杂度为 O(n)。下面详细介绍时间复杂度的计算方法。

(1)O(1) 什么样的算法的时间复杂度为 O(1)呢?为了说明这个问题,首先看一个简单的交换两个变量值的例子。

  1. 1)temp=i;  
  2. 2)i=j;  
  3. 3)j=temp

以上这个例子,相信绝大多数读者都不陌生,三条语句的功能是通过第三方变量 temp达到交换变量 i与变量 j的值的目的。三条单语句的频度均为 1,而该程序段的执行时间是一个与问题规模 n无关的常数。所以,算法的时间复杂度为常数阶,记为 O(1)。

时间复杂度为 O(1)的情况还有很多,例如,在 hash表中找到一个元素、没有循环的简单语句等。

有一个需要注意的问题,在求解算法的时间复杂度时,切记区分 O(1)与 O(n)的情况。如果算法的执行时间不随着问题规模 n的增加而增长,即使算法中有成百上千、成千上万条语句,其执行时间也只是一个常数而已,此时算法的时间复杂度仍然为 O(1),而非想当然的 O(n)。

示例代码如下所示:

  1. bool isPower(int n)  
  2. {  
  3. if (n<1)  
  4. return false;  
  5. int m = n&(n - 1);  
  6. return m == 0;  

上例中,不管 n取值为多少,操作的次数都为 1,所以,其时间复杂度为 O(1)。

(2)O(n^2)首先,看下面一个简单的例子:

  1. 1)sum=0 
  2. 2)for(i=1;i<=n;i++)  
  3. 3) for(j=1;j<=n;j++)  
  4. 4) sum++; (n^2) 

上述代码中,第四行代码在一个双重循环体内,总共执行次数为 n^2。因此这段代码的执行的时间复杂度为 O(n^2)

再看一个简单例子。示例代码如下所示:

  1. 1)for(i=1;i<n;i++)  
  2. 2){  
  3. 3) yy=y+1; (1)  
  4. 4) for(j=0;j<=(2*n);j++)  
  5. 5) x++; (2)  
  6. 6)} 

上述代码中,语句 (1)的频度为 n-1,语句 2的频度为(n-1)*(2n+1)=2n^2-n-1,所以, f(n)=2n^2-n-1+

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

(3)O(n)

O(n)代表算法的运算时间和输入成线性关系。首先,看下面一个示例。

示例代码如下所示:

  1. 1)a=0;  
  2. 2)b=0; (1)  
  3. 3)for(i=1;i<=n;i++) (2)  
  4. 4){  
  5. 5) s=a+b; (3)  
  6. 6) b=a; (4)  
  7. 7) a=s; (5)  
  8. 8)} 

上述代码中,语句 1)的频度为: 2,语句 2)的频度为: n,语句 3)的频度为: n-1,语句 4)的频度为:n-1,语句 5)的频度为: n-1,所以,T(n) = 2+n+3(n-1)=4n-1=O(n)。

时间复杂度为 O(n)的例子很多,例如,在无序数组中找到一个元素、访问链表的第 n 个元素、有一层循环等。

(4)O(logn)

示例代码如下所示:

  1. 1)i=1; (1)  
  2. 2)while(i<=n)  
  3. 3) ii=i*2; (2) 

语句 1)的频度为 1,设语句 2)的频度为 f(n),那么: 2^f(n)<=n,f(n)<=logn。取昀大值 f(n) = logn,所以,T(n)=O(logn)。

再看一个二分查找的例子,其时间复杂度就为 O(logn)。

  1. int BinSrch(Type A[], int i, int n, Type x)  
  2. /*A[i…n]是升序排列,且满足1<=i<=n;*/  
  3. {  
  4. if (n == i)  
  5. {  
  6. if (x == A[i])  
  7. return I;  
  8. else  
  9. return 0;  
  10. }  
  11. else  
  12. {  
  13. int mid = (i + n) / 2;  
  14. if (x == A[mid])  
  15. return mid; //基本操作  
  16. else if (x<A[mid])  
  17. return BinSrh(A, i, mid - 1, x); //递归调用  
  18. else if (x>A[mid])  
  19. return BinSrh(A, mid + 1, n x); //递归调用  
  20. }  

(5)O(n^3)

示例代码如下所示:

  1. 1)for(i=0;i<n;i++)  
  2. 2){  
  3. 3) for(j=0;j<i;j++)  
  4. 4) {  
  5. 5) for(k=0;k<j;k++)  
  6. 6) xx=x+2;  
  7. 7) }  
  8. 8)} 

当 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(n^3)。

通过上面一个示例,不难发现,当有若干个循环语句时,算法的时间复杂度是由嵌套层数昀多的循环语句中昀内层语句的频度 f(n)决定的。该程序段中频度昀大的语句是 5),内循环的执行次数虽然与问题规模 n没有直接关系,但是却与外层循环的变量取值有关,而昀外层循环的次数直接与 n有关,因此,可以从内层循环向外层分析语句 5)的执行次数:则该程序段的时间复杂度为 T(n)=O(n^3/6+低次项)=O(n^3)。

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

Microsoft SQL Server 2005 技术内幕:T-SQL查询

本书是Inside Microsoft SQL Server 2005系列四本著作中的一本。它详细介绍了T-SQL的内部构造,包含了非常全面的编程参考。它提供了使用Tra...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊