使用向量

时间:2019-02-26 10:50:54

标签: c++ arrays 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的一维数组的结构

new double[isize*jsize*ksize]。为了轻松访问(i,j,k)的特定位置,必须重载运算符(是吗?)。

根据我的经验,第一个要快得多,因为它可以轻松访问位置(i,j,k),而后一个必须计算位置并返回值。但是我看到有些人更喜欢后一个而不是第一个。他们为什么偏爱后者?使用第一个有什么缺点吗?

非常感谢。

4 个答案:

答案 0 :(得分:4)

两者之间的主要区别是布局:

UIVisualEffectView

这将为您提供vector<vector<vector<T>>> 的一维数组。
每个项目都是vector<vector<T>>的一维数组。
这些一维数组的每一项将是T的一维数组。

重点是vector<T>本身不存储其内容。它管理一块内存,并将内容存储在那里。这会带来许多不良后果:

  1. 对于尺寸为X·Y·Z的矩阵,您最终将分配vector个内存块。那太慢了,会浪费掉堆。想象一下:大小为20的多维数据集矩阵将触发421次对1 + X + X·Y的调用!
  2. 要访问一个单元格,您有3个间接级别:
    • 您必须访问new对象以获取指向顶级内存块的指针。
    • 然后您必须访问vector<vector<vector<T>>>对象以获取指向第二级内存块的指针。
    • 然后,您必须访问vector<vector<T>>对象以获取指向叶内存块的指针。
    • 然后您才能访问vector<T>数据。
  3. 这些内存块将散布在堆中,从而导致大量的高速缓存未命中,并减慢了整体计算的速度。
  4. 如果您在某个时候弄错了,可能会在矩阵中以不同长度结尾一些行。毕竟,它们是独立的一维数组。

另一方面,具有一个连续的内存块(如T)会给出:

  1. 您分配了1个内存块。没有堆垃圾,O(1)。
  2. 您只需访问指向内存块的指针,然后即可直接查找所需的元素。
  3. 所有矩阵在内存中都是连续的,这对缓存友好。

这几天,一次缓存未命中意味着数十或数百个计算周期的损失,请不要低估缓存友好性。

顺便说一句,您可能没有提到更好的方法:使用众多矩阵库中的一个,它将自动为您处理并提供出色的支持工具(例如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 ++中的数据结构和算法”可以提供有关它的更多详细信息。