日期:2014-05-20 浏览次数:20740 次
前不久去面试了一家公司,面试题是这样的:
?
一个二维数组赋值,有两种循环方法,问是第一种循环效率高,还是第二种循环效率高,代码如下:
?
int a[][] = new int[M][N]; int b[][] = new int [M][N]; int c[][] = new int[M][N]; for(int i=0;i<M;i++) { for(int j=0;j<N;j++) { c[i][j] = a[i][j]*b[i][j]; } } for(int j=0;j<N;j++) { for(int i=0;i<M;i++) { c[i][j] = a[i][j]*b[i][j]; } }
?
当时认为一般编程都是用第一种方法遍历,没有推荐用第二种方法的,应该第一种效率要高。
回来测试了一下,当M=1000,N=2000时,第一种循环用时15秒,第二种循环用时63秒,明显第一种效率要高,可是究竟是什么原因呢。
?
?
用javap分析第一种for循环
public static void main(java.lang.String[]); Code: Stack=5, Locals=6, Args_size=1 0: sipush 1000 3: sipush 2000 6: multianewarray #16, 2; //class "[[I" 10: astore_1 11: sipush 1000 14: sipush 2000 17: multianewarray #16, 2; //class "[[I" 21: astore_2 22: sipush 1000 25: sipush 2000 28: multianewarray #16, 2; //class "[[I" 32: astore_3 33: iconst_0 34: istore 4 36: goto 81 39: iconst_0 40: istore 5 42: goto 70 45: aload_3 //将c的地址压栈 46: iload 4 //将i的值压栈 48: aaload //将上两个值出栈,并将c[i]的值压栈 49: iload 5 //将j的值压栈 51: aload_1 52: iload 4 54: aaload 55: iload 5 57: iaload 58: aload_2 59: iload 4 61: aaload 62: iload 5 64: iaload 65: imul 66: iastore 67: iinc 5, 1 70: iload 5 72: sipush 2000 75: if_icmplt 45 78: iinc 4, 1 81: iload 4 83: sipush 1000 86: if_icmplt 39 89: return LineNumberTable: line 18: 0 line 19: 11 line 20: 22 line 23: 33 line 25: 39 line 27: 45 line 25: 67 line 23: 78 line 43: 89 LocalVariableTable: Start Length Slot Name Signature 0 90 0 args [Ljava/lang/String; 11 79 1 a [[I 22 68 2 b [[I 33 57 3 c [[I 36 53 4 i I 42 36 5 j I ?
第二种for循环
public static void main(java.lang.String[]); Code: Stack=5, Locals=6, Args_size=1 0: sipush 1000 3: sipush 2000 6: multianewarray #16, 2; //class "[[I" 10: astore_1 11: sipush 1000 14: sipush 2000 17: multianewarray #16, 2; //class "[[I" 21: astore_2 22: sipush 1000 25: sipush 2000 28: multianewarray #16, 2; //class "[[I" 32: astore_3 33: iconst_0 34: istore 4 36: goto 81 39: iconst_0 40: istore 5 42: goto 70 45: aload_3 46: iload 5 48: aaload 49: iload 4 51: aload_1 52: iload 5 54: aaload 55: iload 4 57: iaload 58: aload_2 59: iload 5 61: aaload 62: iload 4 64: iaload 65: imul 66: iastore 67: iinc 5, 1 70: iload 5 72: sipush 1000 75: if_icmplt 45 78: iinc 4, 1 81: iload 4 83: sipush 2000 86: if_icmplt 39 89: return LineNumberTable: line 18: 0 line 19: 11 line 20: 22 line 34: 33 line 36: 39 line 38: 45 line 36: 67 line 34: 78 line 43: 89 LocalVariableTable: Start Length Slot Name Signature 0 90 0 args [Ljava/lang/String; 11 79 1 a [[I 22 68 2 b [[I 33 57 3 c [[I 36 53 4 j I 42 36 5 i I
?
?
由此可以看出,每次都是从一维数组开始根据内存地址查找,找到一维数组的地址后再找二维数组的地址,然后将此地址的实际值压栈,类似链表结构。第二种for循环因为首先要将数组a的地址入栈,然后遍历第一维数组,然后用aaload将数组当前下标存放的地址值入栈,由于第一维数组不同,所以需要频繁出栈入栈第一维数组,时间就被浪费在这里。