论坛首页 入门技术论坛

一道简单的面试题

浏览 29497 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-04-20  
wangzaixiang 写道
想起某位大师关软件优化的一段话:

1、编写代码时,不要进行优化。
2、如果没有给你带来麻烦,就不要优化。

说实在的,上面的代码,在99%的情况下,是不需要进行优化的。如果你的情况正好是那个1%,那么你


是有這個印象,嘿嘿.我也被面試過這道題,當時只是把最小的循環放在外面,最大的放在裡面,沒有考慮太多.
也覺的沒有必要考慮的那么複雜了
0 请登录后投票
   发表时间:2010-09-13  
JE帐号 写道
大家数学都很好啊.
看见log就想起对数.我只想起日志... ...

有同感。见到只想到日志,没想到对数……
0 请登录后投票
   发表时间:2010-09-14  
laoshifu 写道
实例化次数计算不对,对于java来说,for语句的初始化只是执行一次。所以对于原代码,优化一和优化二实例化变量的实例化次数都是一。不对之处,多多指教。


你确定吗?
0 请登录后投票
   发表时间:2010-09-15   最后修改:2010-09-15
优化,如果是纯粹的代码优化,我觉得这个题目没有什么意义。
现实中如果要优化,我们得现搞清楚原先这段代码要做什么,根据代码的目标然后提出优化方案。

比如楼主的这个题目,我们就需要搞清楚这个方法的目的是要否要输出遍历值
如果是要遍历值,那么可以这么写:
StringBuffer sb = new StringBuffer(1024);
for (int i = 0; i < 1000; i++){
   for (int j = 0; j < 100; j++){  
       for (int k = 0; k < 10; k++){  
           sb.append(i * j * k);
           sb.append("\n");
        }
   }
}
log(sb.toString());


纯粹的代码优化还是少做,意义不是非常大,除非是严重性能问题。(当然有些人有代码洁癖,另论)。
优化应该是根据功能目的,对原有功能进行更高效的方式实现,所以原先代码实现的目标要先搞清楚。
0 请登录后投票
   发表时间:2010-09-15  
代码如下:
/*
* 0.0.0 ~99.9.0
* 执行次数 100*10*1=1000次
* 执行时间 812
*/
public void doThing(){
for(int i = 0;i<10000;i++) {
     for(int j = 0;j<1000;j++) {
          for(int k = 0;k<100;k++) {
             function(i,j,k);
          }
     }
   }
}

/*
* 0.0.0 ~ 0.9.99
* 执行次数 1*10*100=1000次
* 执行时间 703
*/
public void doOpThing(){
for(int i = 0;i<100;i++) {
     for(int j = 0;j<1000;j++) {
          for(int k = 0;k<10000;k++) {
             function(i,j,k);
          }
     }
   }
}

/*
* 0.0.0 ~ 0.9.99
* 执行次数 1*10*100=1000次
* 执行时间 703
*/
public void doOp2Thing(){
int i,j,k;
for(i = 0;i<100;i++) {
     for(j = 0;j<1000;j++) {
          for(k = 0;k<10000;k++) {
             function(i,j,k);
          }
     }
   }
}
其实这道题的目的并不是让你写出优化的方法,而是考你JVM的编译解析原理.
/ Method descriptor #6 ()V
  // Stack: 4, Locals: 4
  public void doThing();
     0  iconst_0             --将int型0推送至栈顶
     1  istore_1 [i]           --将栈顶int型数值存入第二个本地变量
     2  goto 44              --无条件转移
     5  iconst_0             --将int型0推送至栈顶
     6  istore_2 [j]           --将栈顶int型数值存入第三个本地变量
     7  goto 34              --无条件转移
    10  iconst_0             --将int型0推送至栈顶
    11  istore_3 [k]          --将栈顶int型数值存入第四个本地变量
    12  goto 25             --无条件转移
    15  aload_0 [this]        --将第一个引用类型本地变量推送至栈顶
    16  iload_1 [i]            --将第二个int型本地变量推送至栈顶
    17  iload_2 [j]            --将栈顶int型数值存入第三个本地变量
    18  iload_3 [k]            --将栈顶int型数值存入第四个本地变量
19  invokevirtual org.yclframework.auth.test.dao.ibatis.Optimize.function(int, int, int) : void [24] –执行方法
[以上执行过程都是一致的,两个方法]
    22  iinc 3 1 [k]    --将指定int型变量增加指定值,这里是++
    25  iload_3 [k]    --将第四个int型本地变量推送至栈顶
    26  bipush 100    --将单字节的常量值(-128~127)推送至栈顶
    28  if_icmplt 15   --比较栈顶两int型数值大小,当结果小于0时跳转
    31  iinc 2 1 [j]    --将指定int型变量增加指定值,这里是++
    34  iload_2 [j]    --将栈顶int型数值存入第三个本地变量
    35  sipush 1000   --将一个短整型常量值(-32768~32767)推送至栈顶
    38  if_icmplt 10   --比较栈顶两int型数值大小,当结果小于0时跳转
    41  iinc 1 1 [i]    --将指定int型变量增加指定值,这里是++
    44  iload_1 [i]    --将栈顶int型数值存入第二个本地变量
    45  sipush 10000  --将一个短整型常量值(-32768~32767)推送至栈顶
    48  if_icmplt 5    --比较栈顶两int型数值大小,当结果小于0时跳转
    51  return        --方法返回
      Line numbers:
        [pc: 0, line: 17]
        [pc: 5, line: 18]
        [pc: 10, line: 19]
        [pc: 15, line: 20]
        [pc: 22, line: 19]
        [pc: 31, line: 18]
        [pc: 41, line: 17]
        [pc: 51, line: 24]
      Local variable table:
        [pc: 0, pc: 52] local: this index: 0 type: org.yclframework.auth.test.dao.ibatis.Optimize
        [pc: 2, pc: 51] local: i index: 1 type: int
        [pc: 7, pc: 41] local: j index: 2 type: int
        [pc: 12, pc: 31] local: k index: 3 type: int
编译成Calss的doThing(),其与doOpThing()唯一不同的是执行顺序,其执行顺序如下:
    22  iinc 3 1 [k]
    25  iload_3 [k]
    26  sipush 10000
    29  if_icmplt 15
    32  iinc 2 1 [j]
    35  iload_2 [j]
    36  sipush 1000
    39  if_icmplt 10
    42  iinc 1 1 [i]
    45  iload_1 [i]
    46  bipush 100
    48  if_icmplt 5
51  return
doOpThing()与doOp2Thing()的执行顺序一模一样.
在出入栈操作中,doThing出入栈如下:
变量    出入栈次数 /比较次数
K        100*1000*10000
J        1000*10000
I        10000
在出入栈操作中,doOpThing的出入栈如下:
变量    出入栈次数 /比较次数
K       10000*1000*100
J        1000*100
I        100
其实For循环里面使用的都是局部变量,其变量采用的是本地变量,只初始化一次
接下来都是出入栈和比较的操作,大家可以看到出入栈和比较次数都是相当快的.
采用优化策略却在时间上却提升了10%,虽然是毫妙级别的,但是如果function是一个执行时间很长的程序,那么程序的提升将会很大.

0 请登录后投票
   发表时间:2010-09-15  
  怎么说的都不一样,我都看晕了,上面说的优化方案一和二到底能不能做到优化呢?
0 请登录后投票
   发表时间:2010-09-15  
优化的第一原则,不要优化
0 请登录后投票
   发表时间:2010-10-01  
我个人觉得楼主写得很好,虽然是个简单的问题,但是楼主一步步分析的很透彻。支持楼主。
0 请登录后投票
   发表时间:2010-10-01  
linghongli 写道
 int i, j, k;    
 for (i = 0; i < 10; i++) 
{      
    if(i==0)  
    {
       log(0) ;
       continue;
    }
   else
    {   
       for (j = 1; j < 100; j++)    
         for (k = 1; k < 1000; k++)    
             log(i * j * k); 
     }
}
 

 

 

各位大大,编译器连这个都不能做的话,那就没有意义了。

 

所以不要讨论这个没有必要的话题。

0 请登录后投票
   发表时间:2010-12-02  
javaeye,我爱你,在这里学到很多东西,也很有激励
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics