奇妙bug记录(1)

问题发现

在做一道需要对二维数组遍历的题时,我莫名其妙地使用了列主序的循环顺序,如下:

for(int j = 0;j < n;j++){
        for(int i = 0;i < j;i++){
            dp[i][j] = 2;
        }
    }

对应的逻辑上完全等价的行主序写法如下:

for(int i = 0;i < n;i++){
        for(int j = i + 1;j < n;j++){
            dp[i][j] = 2;
        }
    }

正当我认为必A无疑地交上去的时候:
在这里插入图片描述
可以看到,时间为2045ms,而题目限制2000ms,百思不得其解,找来标程对比,就差在循环顺序了,而行主序的循环顺序,时间竟然比我这列主序的顺序快了一倍:
在这里插入图片描述

分析

仔细想了想(其实是助教的点拨),记得大一的时候学过,其实二维数组在本质上也是一维数组,二者的内存分布并没有不同,都是一片连续的内存空间,做一个联合就知道了:

union{
int a[3][5];
int b[15];
}U;

在上述的联合中,有如下等式:

&U.a == &U.b
&U.a[0] == &U.b[0]
&U.a[1] == &U.b[5]
&U.a[2] == &U.b[10]
&U.a[2][3] == &U.b[13]

并且有如下规律:

&U.a[m][n] == &U.b[m*5+n]//5是a的第二维的长度

回到之前的问题上,出现运行时间如此大差别的原因就很明显了,对于行主序的循环顺序,在寻址时是一个接一个地往后走,每次只需要执行一个下标+1的操作,就可以到达下一个元素,如从dp[0][0]到dp[0][1];而对于列主序的循环顺序,每次需要做一次寻址公式:从dp[0][0]到dp[1][0],内存中做了一次+dp第二维长度的操作,这样下来,在两个维度的长度较小时看不出差别,但是当到达104级别时,反映出来的效率差别就是两倍了。

总结

对二维数组进行遍历时
一定要行主序!
一定要行主序!
一定要行主序!

for(int i = 0;i < n;i++){
	for(int j = 0;j < n;j++){
		a[i][j] = value;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值