分享一道360的C语言笔试题。x是一个行列均为1000的二维数组,下面代码运行效率最高的是哪个?
二维数组大家都很熟悉,正常人遍历二维数组都是一行一行来的,为什么很少有人按列去遍历?
这道笔试题其实考察的就是遍历效率的问题。
选项A,j是行,i是列,很显然 x[i][j] 是按列访问,先是第一列第一个元素,然后第一列第二个元素,以此类推。
选项B和选项C都存在按列访问。只有选项D,属于正常的按行遍历。
那么问题来了,为什么二维数组按行遍历比按列遍历来的快?
这个涉及的问题就太多了,得从CPU高速缓存讲起。
CPU处理速度很快,但是访问内存太慢,严重影响了机器运行效率。于是就出现了高速缓存。
从名字应该能看出,访问它速度确实快。
当CPU发出内存访问请求时,会首先查看缓存内是否有请求的数据,如果有,直接返回,如果没有,就要先把内存中的数据载入缓存,再把它返回给处理器。
由于缓存比内存贵很多,所以它的大小一般都以KB或者MB为单位,如果是一级缓存,那就更小了。
题目中的二维数组大小接近4M,CPU在访问的时候,缓存先从内存抓取数据,而且一般都是抓取相邻整个数据块,简单点理解,就是当前行以及后面的部分数据,这也符合内存访问局部性特征。
三种不同类型的局部性:
时间局部性(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。
程序循环、堆栈等是产生时间局部性的原因。
空间局部性(Spatial Locality):在最近的将来将用到的信息很可能与正在使用的信息在空间地址上是临近的。
顺序局部性(Order Locality):在典型程序中,除转移类指令外,大部分指令是顺序进行的。顺序执行和非顺序执行的比例大致是5:1。此外,对大型数组访问也是顺序的。
指令的顺序执行、数组的连续存放等是产生顺序局部性的原因。
如果二维数组按列遍历,就需要不断的抓取内存的数据,降低程序效率,这也将会失去缓存的意义。