嗨,我是一名研究生,学习使用c ++进行科学计算。我们的一些研究集中在算法的速度上,因此构造足够快的数组结构非常重要。
我已经看到了两种构造3D阵列的方法。 第一个是使用向量库。
vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0)))
这给出了大小为isize x jsize x ksize的3D数组结构。
另一个是使用
构造一个包含大小为isize * jsize * ksize的一维数组的结构 new double[isize*jsize*ksize]
。为了轻松访问(i,j,k)的特定位置,必须重载运算符(是吗?)。
根据我的经验,第一个要快得多,因为它可以轻松访问位置(i,j,k),而后一个必须计算位置并返回值。但是我看到有些人更喜欢后一个而不是第一个。他们为什么偏爱后者?使用第一个有什么缺点吗?
非常感谢。
答案 0 :(得分:4)
两者之间的主要区别是布局:
UIVisualEffectView
这将为您提供vector<vector<vector<T>>>
的一维数组。
每个项目都是vector<vector<T>>
的一维数组。
这些一维数组的每一项将是T的一维数组。
重点是vector<T>
本身不存储其内容。它管理一块内存,并将内容存储在那里。这会带来许多不良后果:
vector
个内存块。那太慢了,会浪费掉堆。想象一下:大小为20的多维数据集矩阵将触发421次对1 + X + X·Y
的调用!new
对象以获取指向顶级内存块的指针。vector<vector<vector<T>>>
对象以获取指向第二级内存块的指针。vector<vector<T>>
对象以获取指向叶内存块的指针。vector<T>
数据。另一方面,具有一个连续的内存块(如T
)会给出:
这几天,一次缓存未命中意味着数十或数百个计算周期的损失,请不要低估缓存友好性。
顺便说一句,您可能没有提到更好的方法:使用众多矩阵库中的一个,它将自动为您处理并提供出色的支持工具(例如SSE加速矩阵操作)。 Eigen是此类库之一,但还有很多。
→您想进行科学计算吗?让一个lib处理样板和基础知识,以便您可以专注于科学计算部分。
答案 1 :(得分:1)
在我看来,std::vector
比普通的普通数组有太多优势。
简而言之,这里是一些:
std::vector
创建内存泄漏要困难得多。仅此一点是最大的优势之一。这与性能无关,但应始终加以考虑。std::vector
是STL的一部分。 C ++的这一部分是最常用的部分之一。成千上万的人使用STL,因此他们每天都会受到“测试”。在过去的几年中,他们进行了如此彻底的优化,因此不再缺乏任何性能。 (如果我看错了,请纠正我)std::vector
处理1、2、3很容易。没有指针处理任何事情……只需通过方法或使用[]
-operator和其他方法访问它即可。答案 2 :(得分:1)
首先,直接在vec ^ 3中访问(i,j,k)的想法有些瑕疵。您所拥有的是一个指针结构,在此过程中需要取消对三个指针的引用。请注意,我不知道这是比计算一维数组中的位置快还是慢。您需要进行测试,并且这可能取决于数据的大小(尤其是是否适合大块数据)。
第二,向量^ 3需要指针和向量大小,这需要更多的内存。在很多情况下,这将是无关紧要的(因为图像呈三次方增长,但内存差异只是二次方),但是如果您的算法确实要填充任何可用的内存,那可能很重要。
第三,原始数组将所有内容存储在连续的内存中,这对于流式传输很有用,并且由于快速的高速缓存访问而对某些算法也很有用。例如,当您将一个3D图像添加到另一个时。
请注意,所有这些都与您可能不需要的超优化有关。 skratchi.at在他的答案中指出的矢量的优点非常强大,我还补充了矢量通常可以提高可读性的优点。如果您没有很好的理由不使用向量,请使用它们。
无论如何,如果您决定使用原始数组,请确保将其包装好,并使类小而简单,以应对有关泄漏等问题。
答案 3 :(得分:0)
欢迎来到。
如果您拥有的一切都是两种选择,那么第一种可能会更好。
Prefer using STL array or vector instead of a C array
您应该避免使用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会做很多事情(例如vectorization),而这些事情将具有对您的实验产生巨大影响。由于很难控制这些看不见的优化,因此这些库的功能可能会导致您得出关于算法的错误结论。
算法的性能和big-o表示法
通常,使用big-O approach分析算法的性能,而没有考虑实际花费的时间,硬件速度或编程语言特征等因素。 Adam Drozdek的著作“ C ++中的数据结构和算法”可以提供有关它的更多详细信息。