二维数组创建方式比较

暑假跟着地质队去跑山了,到现在还没结束,今天休息的时候突然刷到了一篇关于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.rhkb.cn/news/114730.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集成跨境电商ERP(积加、易仓、马帮等)连接多个应用

场景描述&#xff1a; 基于跨境电商开放平台&#xff08;积加、易仓、马帮等&#xff09;能力&#xff0c;无代码集成跨境电商ERP与多个应用互通互连。通过Aboter可搭建业务自动化流程&#xff0c;实现多个应用之间的数据连接。 连接器&#xff1a; 积加ERP马帮ERP易仓ERP……

通过「内网穿透」技术,实现出差期间远程访问企业局域网中的象过河ERP系统

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

投票同款特效样式

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>import url("https://fonts.…

Spring Boot集成MyBatis Plus

文章目录 一、前言二、步骤2.1、步骤 1&#xff1a;创建 Spring Boot 项目2.2、添加依赖2.2.1、基本的Spring和Spring MVC功能2.2.2、MySQL驱动依赖2.2.3、 MyBatis Plus 的依赖 2.3、配置数据库连接2.4、创建实体类2.5、创建 Mapper 接口2.6、编写 Service 层2.7、编写 Contro…

可拖拽编辑的流程图X6

先上图 //index.html&#xff0c;有时候可能加载失败&#xff0c;那就再找一个别的cdn 或者npm下载&#xff0c;如果npm下载&#xff0c; //那么需要全局引入或者局部引入&#xff0c;代码里面写法也会不同&#xff0c;详细的可以看示例<script src"https://cdn.jsdeli…

STM32 CUBEMX CAN通信数据发送失败原因分析

CAN通信是一种数据通信协议&#xff0c;用于在不同设备之间进行通信。它是一种高效的、实时的、可靠的、多主机的、串行通信系统&#xff0c;通常用于汽车电子、工业自动化等领域。CAN通信协议是由德国BOSCH公司于1986年引入&#xff0c;并在欧洲和日本广泛使用。CAN通信具有独…

如何在B站进行学习直播

诸神缄默不语-个人CSDN博文目录 会根据我使用的情况进行持续更新 文章目录 1. 电脑 - 哔哩哔哩直播姬1. 软件的基础使用2. 素材1. 摄像头2. 窗口捕捉3. 游戏进程图片文字浏览器 3. H5插件其他注意事项 2. 手机直播3. iPad直播 1. 电脑 - 哔哩哔哩直播姬 1. 软件的基础使用 电…

Java设计模式:四、行为型模式-04:中介者模式

文章目录 一、定义&#xff1a;中介者模式二、模拟场景&#xff1a;中介者模式三、违背方案&#xff1a;中介者模式3.1 工程结构3.2 创建数据库3.3 JDBC工具类3.4 单元测试 四、改善代码&#xff1a;中介者模式4.1 工程结构4.2 中介者工程结构图4.3 资源和配置类4.3.1 XML配置对…

一文速学-让神经网络不再神秘,一天速学神经网络基础-激活函数(二)

前言 思索了很久到底要不要出深度学习内容&#xff0c;毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新&#xff0c;很多坑都没有填满&#xff0c;而且现在深度学习的文章和学习课程都十分的多&#xff0c;我考虑了很久决定还是得出神经网络系列文章&#xff0c;…

【Linux】线程安全-死锁

文章目录 死锁问题场景1场景2死锁的gdb调试造成死锁的必要条件不可剥夺循环等待互斥条件请求和保持 预防死锁破坏必要条件&#xff0c;循环等待&请求和保持加锁顺序一致避免锁没有被释放资源一次性分配 死锁问题 死锁的两种场景&#xff1a; 场景1 线程加锁之后一直没有将锁…

[FPGA IP系列] BRAM IP参数配置与使用示例

FPGA开发中使用频率非常高的两个IP就是FIFO和BRAM&#xff0c;上一篇文章中已经详细介绍了Vivado FIFO IP&#xff0c;今天我们来聊一聊BRAM IP。 本文将详细介绍Vivado中BRAM IP的配置方式和使用技巧。 一、BRAM IP核的配置 1、打开BRAM IP核 在Vivado的IP Catalog中找到B…

计算机毕设之基于python+echarts+mysql的图书馆可视化管理系统(文档+代码+部署教程)

系统阐述的是一款图书馆可视化管理系统的设计与实现&#xff0c;对于Python、B/S结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了 django框架和MySql数据库技术搭建系统的整体架构…

Royal TSX 6 Mac多协议远程软件

Royal TSX是一款功能强大的远程桌面管理软件&#xff0c;适用于Mac操作系统。它允许用户通过一个集成的界面来管理和访问多个远程计算机和服务器。 Royal TSX支持多种远程协议&#xff0c;包括RDP、VNC、SSH、Telnet和FTP等&#xff0c;可以方便地连接到Windows、Linux、Mac和其…

vue、elementui控制前一级选择后,后一级才会有数据

<el-form-item label"废物类型&#xff1a;"><el-select clearable v-model"queryForm.hswCateType" placeholder"请选择" change"industryCategoryChange" focus"industryCategoryFocus"><el-option v-for&…

pytorch中 nn.Conv2d的简单用法

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, biasTrue,padding_modezeros)参数介绍&#xff1a; in_channels&#xff1a;卷积层输入通道数 out_channels&#xff1a;卷积层输出通道数 kernel_size&#xff1a;卷积层的…

【报错记录】疯狂踩坑之RockyLinux创建Raid1镜像分区,Raid分区在重启后消失了!外加华硕主板使用Raid模式后,硬盘在系统中无法找到问题

前言 为了摆脱对于专业NAS的依赖&#xff0c;我决定专门使用一台Linux服务器安装NAS程序的方式实现NAS功能&#xff0c;这里就需要用到Raid功能&#xff0c;由于目前我只有3块SSD&#xff08;256G500G500G&#xff09;&#xff0c;在ChatGPT的推荐下还是使用一个256G系统盘2块…

Streamlit 讲解专栏(十二):数据可视化-图表绘制详解(下)

文章目录 1 前言2 使用st.vega_lite_chart绘制Vega-Lite图表2.1 示例1&#xff1a;绘制散点图2.2 示例2&#xff1a;自定义主题样式 3 使用st.plotly_chart函数创建Plotly图表3.1 st.plotly_chart函数的基本用法3.2 st.plotly_chart 函数的更多用法 4 Streamlit 与 Bokeh 结合进…

软件测试/测试开发丨Python 学习笔记 之 链表

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26458 链表与数组的区别 复杂度分析 时间复杂度数组链表插入删除O(n)O(1)随机访问O(1)O(n) 其他角度分析 内存连续&#xff0c;利用CPU的机制&#xff0…

ABAP FICO 凭证替代 凭证校验

凭证校验 1.T-CODE--->GGX2--->GBLR-->ZRGGBR000 2.将程序RGGBR000 复制为ZRGGBR000 3.GGB0--》财务会计--》凭证抬头或者行项目维护检验规则 4.OB28 维护特定的公司代码和调用点和确认&#xff0c;活动等级设置为1 5.GGB4-->激活校验 凭证替代 1.T-CODE--->GG…

设计模式之建造者模式与原型模式

目录 建造者模式 简介 使用场景 优缺点 模式结构 实现 原型模式 简介 应用场景 优缺点 模式结构 实现 建造者模式 简介 将复杂对象的构建与表示进行分离&#xff0c;使得同样的构建过程可以创建不同的表示。是一个将复杂的对象分解为多个简单的对象&#xff0c;然…