您的位置:首页 > 其它

for循环效率

2016-04-18 22:13 281 查看
《高质量程序设计语言》提到for循环遍历数组中“先行后列”和“先列后行”有不同的效率。这个勾起了我的兴趣,原文介绍的应该是针对二维数组及其以上的多维数组。效率不同的原因是不同的语言安排数组元素的存储空间的顺序不一样。比如C/C++语言按照“先行后列”的顺序安排数组元素的存储空间。Fortran语言按照“先列后行”的顺序安排数组元素的存储空间。会导致什么后果呢?

引用书中的例子来说明,假设二维数组num
[M],每一行数据刚好占据一页内存(4KB),且C/C++语言按照“先行后列”的顺序安排数组元素的存储空间,如下图所示:



我们来看看不同的循环遍历顺序需要多少次页面调度?

1、“先行后列”。从图中可以发现,一共需要进行12次页面调度。

2、“先列后行”。从图中可以发现,一共需要12 * 1024次页面调度。

这才是两种遍历顺序导致的效率不同的主要原因。

————————————————–分割线———————————————————

OK下面进行代码测试,测试平台是VS2015。测试情况分为四种:

1、创建一个二维数组,先进行“先行后列”后进行“先列后行”遍历。

2、创建一个二维数组,先进行“先列后行”后进行“先行后列”遍历。

3、创建一个二维数组,进行“先列后行”遍历。

4、创建一个二维数组,进行“先行后列”遍历。

代码如下

#include "stdafx.h"

int main()
{
int N, M, i,j,k;
int **num = NULL;
DWORD start, end;
while (fscanf_s(stdin, "%d%d", &N, &M) != EOF) {
//创建二维数组
num = (int **)malloc(N*sizeof(int *));
if (NULL == num) {
printf("malloc error\n");
return -1;
}
for (i = 0; i < N; i++) {
num[i] = (int *)malloc(M*sizeof(int));
if (NULL == num[i]) {
printf("malloc error\n");
k = i;
goto error;
}
}
//先行后列
start = GetTickCount();
for (i = 0; i < N; i++)
for (j = 0; j < M; j++)
num[i][j] = 1;
end = GetTickCount();
printf("first row next colum: \n");
printf("N=%d, M=%d : %dms\n",N,M,end-start);
//先列后行
start = GetTickCount();
for (i = 0; i < M; i++)
for (j = 0; j < N; j++)
num[j][i] = 1;
end = GetTickCount();
printf("first colum next row: \n");
printf("N=%d, M=%d : %dms\n", N, M, end - start);
//释放二维数组
for (i = 0; i < N; i++)
free(num[i]);
free(num);
printf("\n");
}
return 0;
error:
if (NULL != num) {
for (i = 0; i < k; i++) {
if (NULL != num[i])
free(num[i]);
}
free(num);
}
return -1;
}


测试结果

测试情况1



测试情况2



测试情况3



测试情况4



结论(限于测试次数的原因,调度遍历方式对遍历时间的影响只作为观测结果)

调度遍历方式顺序一:“先行后列”-> “先列后行”;

调度遍历方式顺序二:“先列后行”-> “先行后列”;

1、当列数远大于行数时,“先行后列”的遍历时间最小。但在本次测试中发现是与调度遍历方式的顺序无关。

2、当行数远大于列数时,“先行后列”的遍历时间最小。调度顺序二明显使整体的遍历时间变小,但是增加了“先行后列”的遍历时间,减小了“先列后行”的遍历时间。

3、当行列数相等时,“先行后列”的遍历时间最小。调度顺序基本无影响。

4、当行列数都比较小时,遍历顺序基本无影响。

具体的解释可能与cache命中率有关,这里没有进行进一步的分析==
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: