二维数组创建方式比较

news2024/9/23 23:32:41

暑假跟着地质队去跑山了,到现在还没结束,今天休息的时候突然刷到了一篇关于C++二维数组创建方面的文章,我觉得还是非常不错滴,就将其中提到的新方法和我已经使用过的三种方法进行了比较,发现该方法提高了二维数组的分配、访存和运算速度,我用了四种方法:1、常规动态二维数组声明、2、新方法动态二维数组声明、3、Vector容器创建方式1、4、Vector容器创建方式2。

测试数组大小都是20000*20000,这里只展示了其中的5*5的切片,我会先讲各种方法的原理,最后展示各方法的运行时长。

四个函数的功能都是计算直角三角形斜边长。

目录

1、常规动态二维数组声明

2、新方法动态二维数组声明

3、Vector容器声明方法一

4、Vector容器创建方法二

5、绘图解释

6、对比结果

7、程序代码

1、常规动态二维数组声明

这个方式就是最简单也是最常用的方式,先说明一个一维的指针数组,然后每个指针在指向一个数组的地址,就行了,访存则是先找到A[i][j]所对应的指针A[i],再找A[i][j]就行,更通俗的理解就是,这种逐行分配的方法会使得上一行和下一行的地址是不连续的,寻址效率会降低,这里给出代码:

void originalDynamic(int n){
	clock_t start = clock();
	double** a = new double* [n];
	double** b = new double* [n];
	double** c = new double* [n];
	for (int i = 0; i < n; i++) {
		a[i] = new double[n]();
		b[i] = new double[n]();
		c[i] = new double[n]();
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j] = 3.0;
			b[i][j] = 4.0;
			c[i][j] = 0.0;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j],2) + powl(b[i][j],2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << " Original time:" << (end - start)/CLOCKS_PER_SEC << endl;
}

2、新方法动态二维数组声明

出现这个方法的原因是这样的,方法一的地址实际上是不连续的,也就是说访存过程会浪费额外时间,通过将数组地址连续化,就可以节省访存时间,进而提高访存效率。

先贴代码:

void newDynamic(int n){
	clock_t start = clock();
	double** a = new double* [n];
	double** b = new double* [n];
	double** c = new double* [n];
	a[0] = new double[n * n];
	b[0] = new double[n * n];
	c[0] = new double[n * n];
	for (int i = 1; i < n; i++) {
		a[i] = a[0] + i * n;
		b[i] = b[0] + i * n;
		c[i] = c[0] + i * n;
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j] = 3.0;
			b[i][j] = 4.0;
			c[i][j] = 0.0;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "New time:" << (end - start)/CLOCKS_PER_SEC  << endl;
}

只需要看6-13行就行,可以看到再第一行的首地址申请空间的时候就把整个二维数组的空间全部申请了,再把其余隔行都依次对应到首地址之后的地址,这样就使得整个数组的地址连续化,从而提高了访存效率。咋说呢,我觉得这个有点像C++中一维数组变二维数组,看代码的逻辑上也很像:

//一维数组做二维数组使用:
double *array1=new double[n*n];
//二维数组的下标对应方式就是:
array[i][j]=array1[i*row+j];

上述的这个方式我之前用CUDA做东西的时候用的很多,今天这个二维数组声明方法实际上就是上述的一维数组做二维数组方法的变形。

3、Vector容器声明方法一

个人觉得这个方法是Vector数组声明方法中最简单的,也是最高效的一种,这里就不讲什么原理了,会使用就好:

void usingVectorway1(int n){
	clock_t start = clock();
	vector<vector<double>>a(n, vector<double>(n, 3.0));
	vector<vector<double>>b(n, vector<double>(n, 4.0));
	vector<vector<double>>c(n, vector<double>(n, 0.0));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "vector Way1 time:" << (end - start)/CLOCKS_PER_SEC<< endl;

}

直接按照3-5行的声明方式声明,容器类就会给你创建好。

4、Vector容器创建方法二

这个方法是一种笨办法,最慢也最不推荐使用,但是还是可以作为一个反例来给出:

但这个方法是最好理解的:先创建一个大小为n的vector数组,然后每个都resize成一个大小为n的一维数组,再遍历,赋值,特别麻烦,和第一种有着异曲同工之妙,但是也是最慢的。

void usingVectorway2(int n){
	clock_t start = clock();
	vector<vector<double>> a(n);
	vector<vector<double>> b(n);
	vector<vector<double>> c(n);
	for (int i = 0; i < n; i++) {
		a[i].resize(n);
		b[i].resize(n);
		c[i].resize(n);
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j]=3.0;
			b[i][j]=4.0;
			c[i][j]=1.0;
}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "Vector Way2 time:" << (end - start)/CLOCKS_PER_SEC  << endl;
}

5、绘图解释

第一种和第四种方法原理是这样的:

标题方法一和方法四

 第二种方法:

方法二

 这下就很清楚了。

6、对比结果

最后我们来看看这四种方法的运行结果,主要是看他们的运行时长:

运行时长对比

 可以看出,新方法(方法二)的速度最快,而方法四的速度最慢,这说明我们改变声明和访存方式之后,分配、访存、计算速度是有所提升的,新方法是行之有效的。

7、程序代码

这里贴上所有程序代码,不写注释了,上面各函数都讲了:

#include<iostream>
#include<vector>
#include<ctime>
using namespace std;
void originalDynamic(int n);
void newDynamic(int n);
void usingVectorway1(int n);
void usingVectorway2(int n);
int main() {
	const int n = 20000;
	originalDynamic(n);
	newDynamic(n);
	usingVectorway1(n);
	usingVectorway2(n);
}

void originalDynamic(int n){
	clock_t start = clock();
	double** a = new double* [n];
	double** b = new double* [n];
	double** c = new double* [n];
	for (int i = 0; i < n; i++) {
		a[i] = new double[n]();
		b[i] = new double[n]();
		c[i] = new double[n]();
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j] = 3.0;
			b[i][j] = 4.0;
			c[i][j] = 0.0;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j],2) + powl(b[i][j],2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << " Original time:" << (end - start)/CLOCKS_PER_SEC << endl;
}

void newDynamic(int n){
	clock_t start = clock();
	double** a = new double* [n];
	double** b = new double* [n];
	double** c = new double* [n];
	a[0] = new double[n * n];
	b[0] = new double[n * n];
	c[0] = new double[n * n];
	for (int i = 1; i < n; i++) {
		a[i] = a[0] + i * n;
		b[i] = b[0] + i * n;
		c[i] = c[0] + i * n;
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j] = 3.0;
			b[i][j] = 4.0;
			c[i][j] = 0.0;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "New time:" << (end - start)/CLOCKS_PER_SEC  << endl;
}

void usingVectorway1(int n){
	clock_t start = clock();
	vector<vector<double>>a(n, vector<double>(n, 3.0));
	vector<vector<double>>b(n, vector<double>(n, 4.0));
	vector<vector<double>>c(n, vector<double>(n, 0.0));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "vector Way1 time:" << (end - start)/CLOCKS_PER_SEC<< endl;

}

void usingVectorway2(int n){
	clock_t start = clock();
	vector<vector<double>> a(n);
	vector<vector<double>> b(n);
	vector<vector<double>> c(n);
	for (int i = 0; i < n; i++) {
		a[i].resize(n);
		b[i].resize(n);
		c[i].resize(n);
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			a[i][j]=3.0;
			b[i][j]=4.0;
			c[i][j]=1.0;
}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			c[i][j] = sqrt(powl(a[i][j], 2) + powl(b[i][j], 2));
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << c[i][j] << '\t';
		}
		cout << endl;
	}
	clock_t end = clock();
	cout << "Vector Way2 time:" << (end - start)/CLOCKS_PER_SEC  << endl;
}

ok,学到一种新方法还是很高兴的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/958668.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习前沿:改进自身缺陷,满足新战略

前机械师&#xff08; 来源) 一、说明 机器学习在人工智能历史上扮演重要角色&#xff0c;然而&#xff0c;存在问题也不少。为了适应新时代和新任务&#xff0c;不做出重大改进是不可能的&#xff0c;本篇就一些突出问题和改进做出讨论。以便读者掌握未来的思路和方向。 二、机…

Python自动化运维之命令行参数(sys、argparse模块)

目录 一、sys.argv属性变量 二、argparse模块 一、sys.argv属性变量 sys.argv变量里面保存着命令行的参数列表。首个元素值为执行py脚本文件所在的路径。可以使用切片的方式来获取非脚本文件名的其它所有参数。 二、argparse模块 可以轻松地编写出用户体验友好的命令行界面…

【Linux】线程安全-互斥同步

文章目录 线程安全问题的引入线程互斥互斥概念互斥锁互斥锁的计数器当中如何保证原子性互斥锁基础API初始化互斥锁变量函数动态初始化静态初始化 加锁函数阻塞加锁非阻塞加锁带有超时时间的加锁 解锁函数销毁互斥锁函数 线程同步线程同步的必要性条件变量条件变量的使用原理条件…

冠达管理:龙头股票是什么意思?

龙头股票是指在某个职业或板块中市值最大、盈余才能最强、发展前景最好的上市公司。可以说&#xff0c;龙头股票是该职业或板块的代表。 那么&#xff0c;为什么龙头股票具有如此重要的地位&#xff1f;与其他股票比较&#xff0c;有哪些优势和下风&#xff1f;这篇文章将从多…

Stable Diffusion 从入门到企业级应用010

一、前言 本文是《Stable Diffusion 从入门到企业级应用实战》系列的第四部分能力进阶篇《Stable Diffusion ControlNet v1.1 图像精准控制》的第010篇 利用Stable Diffusion ControlNet 法线贴图模型精准控制图像生成。本部分内容&#xff0c;位于整个Stable Diffusion生态体…

节能减排数远程控制二次开发网关BL304

钡铼技术嵌入式ARM控制器BL304在各个领域的应用越来越广泛。从物联网、工业物联网&#xff0c;到数字化工厂、工业自动化&#xff0c;再到智慧医疗、智慧电力、智慧安防&#xff0c;以及车载、轨道交通、通讯、充电桩、智能家居、人机交互等&#xff0c;BL304都发挥着举足轻重的…

哈弗枭龙MAX将在9月上旬推出首次OTA升级,保不住电?不存在的

9月1日消息&#xff0c;哈弗品牌执行副总经理乔心昱昨晚通过个人微博向网友们回应了关于哈弗枭龙MAX电池保持的问题。乔心昱表示&#xff0c;在与紧急技术团队确认后&#xff0c;他首先澄清了一个误会&#xff1a;大家可以放心使用&#xff0c;正常情况下没有电池问题。 此外&a…

2023开学啦《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

2023开学啦《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

【UE 材质】常用向量运算节点——点积、叉积、归一化

目录 一、点积 二、叉积 三、归一化 一、点积 点积&#xff0c;也称为内积或数量积&#xff0c;是一种用于计算两个向量之间关系的操作。对于两个三维向量 A&#xff08;a1,a2,a3&#xff09;和 B(b1,b2,b3)&#xff0c;它们的点积可以用以下公式表示&#xff1a; ABa1​⋅…

【业务功能篇93】微服务-springcloud-多线程-异步处理-异步编排-CompletableFutrue-实战运用

异步处理编排 我们可以在商品详细信息查询的位置实现CompletableFuture的异步编排处理。 根据业务分析&#xff1a;3.4.5数据接口的入参信息需要来源于1数据接口的返回信息&#xff0c;也就是skuid 所以可以设计 1 3 4 5 串行线程 &#xff0c;而 3 4 5依赖1 &#xff0c;需要等…

2023下半年深圳软考信息系统项目管理师认证开班中,快来报名

信息系统项目管理师是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目之一&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资…

运营超5000万公里,再签700辆订单,嬴彻卡车NOA引领商用车自动驾驶商业化

从主动安全到智能驾驶&#xff0c;商用车自动驾驶商业化进程已经明显提速。 8月29日&#xff0c;嬴彻科技举办以“奔跑吧 卡车NOA”为主题的第二届嬴彻科技日&#xff0c;宣布嬴彻卡车NOA&#xff08;导航辅助驾驶&#xff09;已经突破5000万公里&#xff0c;并实现安全运营零…

骨传导耳机有副作用吗?骨感耳机有什么弊端?

骨传导耳机是通过振动骨骼传达声音信号到内耳而非通过耳道传输的&#xff0c;因此相较于传统耳机&#xff0c;其对耳道和鼓膜的刺激较小&#xff0c;可以说骨传导耳机在使用中是没有副作用的。 不过&#xff0c;任何产品都不是十全十美的&#xff0c;那么骨传导耳机有什么弊端…

python 笔记(3)——request

目录 1、使用requests发送http请求 1-1&#xff09;发送get请求 1-2&#xff09;发送 post 请求 1-3&#xff09;发送 get 请求下载网络图片 1-4&#xff09;使用 post 上传文件 1-5&#xff09;自动维护 session 的方式 2、使用 os.popen 执行cmd命令 3、基于 beautif…

Git学习——细节补充

Git学习——细节补充 1. git diff2. git log3. git reset4. git reflog5. 提交撤销5.1 当你改乱了工作区某个文件的内容&#xff0c;想直接丢弃工作区的修改时5.2 当提交到了stage区后&#xff0c;想要退回 6. git remote7. git pull origin master --no-rebase8. 分支管理9. g…

【100天精通python】Day46:python网络编程_网络编程基础与入门

目录 专栏导读 1 网络编程的基础 2. 基本概念和协议 2.1 计算机网络基础 2.2 网络协议、IP地址、端口号 2.3 常见网络协议 3. 套接字编程 3.1 套接字的基本概念 3.2 套接字的基本操作 3.3 套接字通信模型和方法&#xff1a;send、recv 3.3.1 TCP通信模型 3.3.2 U…

linux-samba-window登不上

登不上查了很久发现是防火墙导致的 sudo firewall-cmd --list-all //查看所有的防火墙信息sudo firewall-cmd --permanent --zonepublic --add-servicesamba //service里添加sambafirewall-cmd --reload //重启 便可以登录了,小问题

VirtualBox7+Ubuntu22集群规划

1. 目的: 新入手了一台小主机&#xff08;8核 / Intel(R) Xeon(R) W-10885M CPU 2.40GHz 2.40 GHz, 16vCpu / 64G RAM / 系统类型 64 位操作系统, 基于 x64 的处理器&#xff09;&#xff0c;原装了一套Win11专业版&#xff0c;打算用VirtualBox 虚拟一个集群。 2. …

电脑可以上网,微信都可以用,但浏览器打不开网页

可以试试设置DNS&#xff08;其他windows版本步骤&#xff09;&#xff1a; 1.打开控制面板 2.网络和Internet 3.查看网络计算机和设备 4.按照下图步骤&#xff1a; 5.按下图进行

深度学习论文分享(九)Unifying Motion Deblurring and Frame Interpolation with Events

深度学习论文分享&#xff08;九&#xff09;Unifying Motion Deblurring and Frame Interpolation with Events 前言Abstract1. Introduction2. Related Work2.1. Frame Interpolation2.2. Motion Deblurring2.3. Joint Deblurring and Interpolation 3. Problem Statement4. …