[英]Declaring 3D array structure in c++ using vector
嗨,我是一名研究生,学习使用c ++进行科学计算。 我们的一些研究集中在算法的速度上,因此构造足够快的数组结构非常重要。
我已经看到了构造3D阵列的两种方法。 第一个是使用向量库。
vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0)))
这给出了大小为isize x jsize x ksize的3D数组结构。
另一个是使用以下命令构造一个包含大小为isize * jsize * ksize的1d数组的结构
new double[isize*jsize*ksize]
。 为了轻松访问(i,j,k)的特定位置,必须重载运算符(对吗?)。
根据我的经验,第一个要快得多,因为它可以轻松访问位置(i,j,k),而后一个则必须计算位置并返回值。 但是我看到有些人更喜欢后一个而不是第一个。 他们为什么偏爱后者? 使用第一个有什么缺点吗?
非常感谢。
两者之间的主要区别是布局:
vector<vector<vector<T>>>
这将为您提供vector<vector<T>>
一维数组。
每个项目都是vector<T>
一维数组。
这些一维数组的每一项将是T的一维数组。
关键是, vector
本身不存储其内容。 它管理一块内存,并将内容存储在那里。 这会带来许多不良后果:
1 + X + X·Y
内存块。 那太慢了,会浪费掉堆。 想象一下:大小为20的多维数据集矩阵将触发421个对new
调用! vector<vector<vector<T>>>
对象以获取指向顶级内存块的指针。 vector<vector<T>>
对象以获取指向第二级内存块的指针。 vector<T>
对象以获取指向叶内存块的指针。 T
数据。 另一方面,拥有一个连续的内存块(如new T[X * Y * Z]
)将得出:
那些日子里,单个缓存未命中意味着数十或数百个计算周期的损失,请不要低估缓存友好性。
顺便说一句,您可能没有提到更好的方法:使用众多矩阵库中的一种,该库将自动为您处理并提供出色的支持工具(例如SSE加速矩阵操作)。 Eigen是这样的图书馆之一,但还有很多其他图书馆。
→您想进行科学计算吗? 让lib处理样板和基础知识,以便您可以专注于科学计算部分。
在我看来, std::vector
与普通的普通数组相比有太多优势。
简而言之,这里是一些:
std::vector
创建内存泄漏要困难得多。 仅此一点是最大的优势之一。 这与性能无关,但应始终考虑。 std::vector
是STL的一部分。 C ++的这一部分是最常用的部分之一。 成千上万的人使用STL,因此他们每天都会受到“测试”。 在过去的几年中,他们进行了如此彻底的优化,因此不再缺乏任何性能。 (请纠正我,如果我看到这个错误) std::vector
处理很容易成为1,2,3。没有指针就什么都不做...只需通过方法或使用[]
-operator和更多其他方法来访问它。 首先,直接在vec ^ 3中访问(i,j,k)的想法有些缺陷。 您所拥有的是一个指针结构,在此过程中需要取消对三个指针的引用。 请注意,我不知道这是比计算一维数组中的位置快还是慢。 您需要进行测试,并且这可能取决于数据的大小(尤其是是否适合大块数据)。
其次,向量^ 3需要指针和向量大小,这需要更多的内存。 在很多情况下,这将是无关紧要的(因为图像呈三次方增长,但内存差异仅二次方增长),但是如果您的算法确实要填充任何可用的内存,那可能很重要。
第三,原始数组将所有内容存储在连续的内存中,这有利于流传输,并且由于快速的高速缓存访问而对于某些算法也很有利。 例如,当您将一个3D图像添加到另一个时。
请注意,所有这些都与您可能不需要的超优化有关。 skratchi.at在他的答案中指出的矢量的优点非常强大,我还补充了矢量通常可以提高可读性的优点。 如果没有充分的理由不使用向量,请使用它们。
无论如何,如果您决定使用原始数组,请确保将其包装好并保持类的大小和简单性,以解决有关泄漏等问题。
欢迎来到SO。
如果您拥有的一切都是两种选择,那么第一种可能会更好。
您应该避免使用C ++普通数组,因为您需要使用new/delete
和其他样板代码(如跟踪大小/检查范围)来管理自己的内存分配/取消分配。 用明确的话说: “ C数组不太安全,并且与数组和向量相比没有任何优势。”
但是,在第一种选择中存在一些重要的缺点。 我想强调的是:
std::vector<std::vector<std::vector<T>>>
不是3维矩阵。 在矩阵中,所有行的大小必须相同。 另一方面,在“向量的向量”中,不能保证所有嵌套的向量都具有相同的长度。 原因是向量是@spectras答案中指出的线性一维结构。 因此,为避免各种不良行为或意外行为,您必须在代码中包括防护措施,以确保得到保证的矩形不变式。
幸运的是,第一种选择不是您手中可能只有的一种。
例如,您可以将c样式数组替换为std :: array:
const int n = i_size * j_size * k_size;
std::array<int, n> myFlattenMatrix;
或使用std::vector
来改变矩阵尺寸。
通过其3个坐标访问元素
关于你的问题
为了轻松访问(i,j,k)的特定位置,必须重载运算符(对吗?)。
不完全是。 由于std :: vector和array都没有3参数运算符,因此您不能重载它。 但是您可以创建一个模板类或函数来为您包装它。 无论如何,您都必须参考这三个向量或计算线性存储中元素的展平索引。
考虑不要在实验中使用像Eigen这样的第三方矩阵库
您不是将其编码用于生产,而是用于研究目的。 特别是,您的研究完全是关于算法的性能。 在那种情况下,我不建议绝对不要使用像Eigen这样的第三方库。 当然,这取决于您愿意收集什么样的“算法速度”指标,但是例如Eigen会做很多事情(例如矢量化 ),这会对您产生巨大影响实验。 由于很难控制这些看不见的优化,因此这些库的功能可能会导致您得出关于算法的错误结论。
算法的性能和big-o表示法
通常,算法的性能是使用big-O方法进行分析的,其中不考虑实际花费的时间,硬件速度或编程语言特性等因素。 Adam Drozdek的书“ C ++中的数据结构和算法”可以提供有关它的更多详细信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.