C语言数组按行优先遍历

参考例子:按行遍历和按列遍历哪一个更快一些?_Master.Jiang的博客-CSDN博客_行遍历和列遍历

行优先与列优先遍历opencv中Mat数据类型的效率差异_liu_jie_bin的博客-CSDN博客_行优先遍历与列优先遍历命中率

对于C来说,访问二维数组的顺序不同,时间消耗也是不同的。行优先遍历和列优先遍历进行对比,行优先更佳。

 编写一个简单程序进行测试:

#include
#include
int a[20005][20005]={0};

int main()
{
    double s1,s2;
    int i,j;
    s1=clock();
    for(i=1;i<=10;i++){
        for(j=1;j<=10;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("10*10数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=10;i++){
        for(j=1;j<=10;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("10*10数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=100;i++){
        for(j=1;j<=100;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("100*100数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=100;i++){
        for(j=1;j<=100;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("100*100数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=500;i++){
        for(j=1;j<=500;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("500*500数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=500;i++){
        for(j=1;j<=500;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("500*500数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=1000;i++){
        for(j=1;j<=1000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("1000*1000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=1000;i++){
        for(j=1;j<=1000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("1000*1000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=2000;i++){
        for(j=1;j<=2000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("2000*2000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=2000;i++){
        for(j=1;j<=2000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("2000*2000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=3000;i++){
        for(j=1;j<=3000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("3000*3000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=3000;i++){
        for(j=1;j<=3000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("3000*3000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=4000;i++){
        for(j=1;j<=4000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("4000*4000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=4000;i++){
        for(j=1;j<=4000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("4000*4000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=5000;i++){
        for(j=1;j<=5000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("5000*5000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=5000;i++){
        for(j=1;j<=5000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("5000*5000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=6000;i++){
        for(j=1;j<=6000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("6000*6000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=6000;i++){
        for(j=1;j<=6000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("6000*6000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=7000;i++){
        for(j=1;j<=7000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("7000*7000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=7000;i++){
        for(j=1;j<=7000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("7000*7000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=8000;i++){
        for(j=1;j<=8000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("8000*8000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=8000;i++){
        for(j=1;j<=8000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("8000*8000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=9000;i++){
        for(j=1;j<=9000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("9000*9000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=9000;i++){
        for(j=1;j<=9000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("9000*9000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=10000;i++){
        for(j=1;j<=10000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("10000*10000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=10000;i++){
        for(j=1;j<=10000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("10000*10000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=12000;i++){
        for(j=1;j<=12000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("12000*12000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=12000;i++){
        for(j=1;j<=12000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("12000*12000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=14000;i++){
        for(j=1;j<=14000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("14000*14000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=14000;i++){
        for(j=1;j<=14000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("14000*14000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=16000;i++){
        for(j=1;j<=16000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("16000*16000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=16000;i++){
        for(j=1;j<=16000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("16000*16000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=18000;i++){
        for(j=1;j<=18000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("18000*18000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=18000;i++){
        for(j=1;j<=18000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("18000*18000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=20000;i++){
        for(j=1;j<=20000;j++){
            a[i][j]=1;
        }
    }
    s2=clock();
    printf("20000*20000数组按行遍历运行时间:%.12f s\n",(s2-s1)/CLOCKS_PER_SEC);
    s1=clock();
    for(i=1;i<=20000;i++){
        for(j=1;j<=20000;j++){
            a[j][i]=1;
        }
    }
    s2=clock();
    printf("20000*20000数组按列遍历运行时间:%.12f s\n\n",(s2-s1)/CLOCKS_PER_SEC);
    return 0;
}

其运行结果ubuntu16虚拟机:

u16@ubuntu:~/test_cpp$ ./build.sh 
-- Host Architecture = x86_64

10*10数组按行遍历运行时间:0.000011000000 s
10*10数组按列遍历运行时间:0.000000000000 s

100*100数组按行遍历运行时间:0.000113000000 s
100*100数组按列遍历运行时间:0.000005000000 s

500*500数组按行遍历运行时间:0.000994000000 s
500*500数组按列遍历运行时间:0.000163000000 s

1000*1000数组按行遍历运行时间:0.001463000000 s
1000*1000数组按列遍历运行时间:0.001618000000 s

2000*2000数组按行遍历运行时间:0.005460000000 s
2000*2000数组按列遍历运行时间:0.020687000000 s

3000*3000数组按行遍历运行时间:0.010454000000 s
3000*3000数组按列遍历运行时间:0.050492000000 s

4000*4000数组按行遍历运行时间:0.015124000000 s
4000*4000数组按列遍历运行时间:0.093347000000 s

5000*5000数组按行遍历运行时间:0.019124000000 s
5000*5000数组按列遍历运行时间:0.139494000000 s

6000*6000数组按行遍历运行时间:0.028529000000 s
6000*6000数组按列遍历运行时间:0.194977000000 s

7000*7000数组按行遍历运行时间:0.035542000000 s
7000*7000数组按列遍历运行时间:0.251729000000 s

8000*8000数组按行遍历运行时间:0.053196000000 s
8000*8000数组按列遍历运行时间:0.310974000000 s

9000*9000数组按行遍历运行时间:0.064045000000 s
9000*9000数组按列遍历运行时间:0.381296000000 s

10000*10000数组按行遍历运行时间:0.076950000000 s
10000*10000数组按列遍历运行时间:0.439071000000 s

12000*12000数组按行遍历运行时间:0.104241000000 s
12000*12000数组按列遍历运行时间:0.591645000000 s

14000*14000数组按行遍历运行时间:0.135862000000 s
14000*14000数组按列遍历运行时间:0.767986000000 s

16000*16000数组按行遍历运行时间:0.175874000000 s
16000*16000数组按列遍历运行时间:1.055006000000 s

18000*18000数组按行遍历运行时间:0.207204000000 s
18000*18000数组按列遍历运行时间:1.295405000000 s

20000*20000数组按行遍历运行时间:0.228332000000 s
20000*20000数组按列遍历运行时间:1.554783000000 s

当数组大小较小时,按行遍历和按列遍历的时间差不多;随着数组大小的增大,二者的运行时间均有增长,但是增长幅度不同。显然按行遍历的增长幅度要小于按列遍历。 PS,原文也对比了matlab,可以看到对于计算来说,C++的速度明显快于Matlab。

因为在C++中,存储的二维数组是以行优先的,我们正常使用的逻辑也是如此。

在这里插入图片描述

         是因为cpu在访问内存地址的时候,首先访问的是虚拟内存,检查TLB,映射成对应的物理地址进行数据访问。如果命中,会得到其物理地址,之后会访问cache缓存,如果cache中有要访问的数据,那么本次访问就结束,如果没有,就到内存中寻找,并更新cache缓存;如果TLB不命中,那么那么系统内核会调用缺页异常处理程序去处理,这个过程中会进行页替换等操作,最终取得要访问的数据。而内存的物理地址中,二维数组是以行优先的顺序存储,测试图像数据大小为4096X1200字节,假设内存页为4096字节,那么按行优先遍历,遍历完一行则中断一次缺页,整个过程只需要中断1200次缺页异常,进行页替换。而按列优先遍历,每遍历一个元素便中断一次缺页异常。

        opencv使用二维数组实现cv::Mat数据结构,通常一张图片为2000*2000大小,若以行遍历通常会比列遍历的快10ms级别。

        在内存中,数组是连续分布的。数组在内存中是按行优先存储的,在虚存环境下,如果整个数组没有在内存中的话可以比列优先减少内存换进换出的次数。就算整个数组都在内存中,列优先访问a[i][j]还要计算一次乘法,行优先只需加一即可,换言之,乘法的“代价” 远大于加法。

opencv 的Mat类

原文链接:https://blog.csdn.net/u012058778/article/details/90764430

如果使用Mat类,我们得到的好处是:

  1. 不需要手动申请一块内存;
  2. 在不需要时不用再手动释放内存;
  3. 可以通过类的封装,方便的获取到数据的相关信息。
  4. 它利用了类的特性,将内存管理和数据信息封装在类的内部,用户只需要对Mat类对象进行数据或面向对象操作即可。
    Mat类分为两个部分:矩阵头和矩阵数据。如果我们在操作一副图像的数据量时,矩阵数据的大小很大(一般约有1M的数据量),那么拷贝和赋值函数所作的操作如果的深拷贝的话,效率会大大的降低。所以,Opencv的做法是只复制其矩阵头信息,而矩阵数据采用引用的方式,即多个Mat对象共享同一个矩阵数据,这里使用的原理类似c++11中的共享指针。。
cv::Mat A = cv::imread("erode.jpg");
	cv::Mat B(A);
	cv::Mat C = A;

	printf("A.data = %p\nB.data = %p\nC.data = %p\n", A.data, B.data, C.data);

三个矩阵的数据是指向同一块矩阵数据。

遍历Mat的数据时,和上面描述的相同,按照行优先,通过指针的方式读取最快。

#include  
   
 int height = 5;
	int width = 5;

	cv::Mat image  = cv::Mat::zeros(height, width, CV_16UC2);
	cv::Mat image1  = cv::Mat::zeros(height, width, CV_16UC2);
	cv::Mat image2  = cv::Mat::zeros(height, width, CV_16UC2);
	chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for (int row = 0; row < height; row++)
	{	
		//指向矩阵当前行的指针
		Vec *data_Ptr = image.ptr> (row);
		//可以将data_Ptr看出一个数组,data_Ptr[col]代表了第几个元素
		//每个元素的数据类型是,包含了2个无符号整型的元素
		for (int col = 0; col < width; col++)
		{
			data_Ptr[col][0] = 5;
			data_Ptr[col][1] = 2;
        }
	}
	chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
	chrono::duration time_used = chrono::duration_cast>(t2-t1);
	cout << "The first method cost time is "<>(row,col)[0] = 5;
			image1.at>(row,col)[1] = 2;
        }
	}
	chrono::steady_clock::time_point t3 = chrono::steady_clock::now();
	time_used = chrono::duration_cast>(t3-t2);
	cout << "The second method cost time is "<

你可能感兴趣的:(c++)