1D或2D阵列,什么更快?

时间:2013-06-23 10:36:25

标签: c++ c arrays

我需要表示一个2D场(轴x,y),我遇到了一个问题:我应该使用一维数组还是2D数组?

我可以想象,重新计算1D数组的索引(y + x * n)可能比使用2D数组(x,y)慢,但我可以想象1D可能在CPU缓存中。

我做了一些谷歌搜索,但只发现了关于静态数组的页面(并说明1D和2D基本相同)。但我的阵列必须是我的动态。

那么,什么是

  1. 更快,
  2. 较小(RAM)
  3. 动态1D阵列还是动态2D阵列?

    谢谢:)

6 个答案:

答案 0 :(得分:17)

除非你在讨论静态数组, 1D更快

这是一维数组(std::vector<T>)的内存布局:

+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+

动态二维数组(std::vector<std::vector<T>>)的情况也是如此:

+---+---+---+
| * | * | * |
+-|-+-|-+-|-+
  |   |   V
  |   | +---+---+---+
  |   | |   |   |   |
  |   | +---+---+---+
  |   V
  | +---+---+---+
  | |   |   |   |
  | +---+---+---+
  V
+---+---+---+
|   |   |   |
+---+---+---+

显然,2D情况会丢失缓存局部性并使用更多内存。它还引入了一个额外的间接(因此引入了一个额外的指针),但是第一个数组有计算索引的开销,所以它们或多或少都有。

答案 1 :(得分:8)

1D和2D静态阵列

  • 尺寸:两者都需要相同的内存量。

  • 速度:您可以假设没有速度差异,因为这两个阵列的内存应该是连续的( 整个2D数组应该在内存中显示为一个块而不是一个 一堆块散布在记忆中)。 (这可能是编译器 但是依赖。)

1D和2D动态数组

  • 大小: 2D阵列比1D阵列需要更多的内存,因为2D阵列中需要指针指向分配的1D阵列集。 (当我们谈论的是非常大的阵列时,这一点很小。对于小型阵列,相对而言,这一点可能相当大。)

  • 速度: 1D阵列可能比2D阵列更快,因为2D阵列的内存不会是连续的,因此缓存未命中会成为问题。

    < / LI>

使用什么有用,似乎最合乎逻辑,如果你遇到速度问题,那么重构。

答案 2 :(得分:5)

现有答案都只将1-D数组与指针数组进行比较。

在C(但不是C ++)中有第三种选择;您可以拥有一个动态分配的连续二维数组,并具有运行时维度:

int (*p)[num_columns] = malloc(num_rows * sizeof *p);

,访问方式与p[row_index][col_index]类似。

我希望这与1-D数组的情况非常相似,但它为您提供了更好的语法来访问单元格。

在C ++中,您可以通过定义一个在内部维护一维数组的类来实现类似的功能,但可以使用重载运算符通过二维数组访问语法公开它。我再次希望它具有与普通1-D阵列相似或相同的性能。

答案 3 :(得分:4)

1D和2D阵列的另一个区别在于内存分配。我们无法确定2D阵列的成员是否有序。

答案 4 :(得分:1)

这实际上取决于2D阵列的实现方式。

int a[200], b[10][20], *c[10], *d[10];
for (ii = 0; ii < 10; ++ii)
{
   c[ii] = &b[ii][0];
   d[ii] = (int*) malloc(20 * sizeof(int));    // The cast for C++ only.
}

这里有3个实现:b,c和d 访问b [x] [y]或[x * 20 + y]会有很多差异,因为一个是你在做计算,另一个是编译器为你做的。 c [x] [y]和d [x] [y]较慢,因为机器必须找到c [x]指向的地址,然后从那里访问第y个元素。这不是一个直接的计算。在某些机器上(例如AS400有36个字节(非位)指针),指针访问速度极慢。它完全取决于使用的架构。在x86类型的体系结构中,a和b的速度相同,c和d比b慢。

答案 5 :(得分:0)

我喜欢Pixelchemist提供的彻底答案。该解决方案的更简单版本可以如下。首先,声明尺寸:

constexpr int M = 16; // rows
constexpr int N = 16; // columns
constexpr int P = 16; // planes

接下来,创建一个别名,并获取和设置方法:

template<typename T>
using Vector = std::vector<T>;

template<typename T>
inline T& set_elem(vector<T>& m_, size_t i_, size_t j_, size_t k_)
{
    // check indexes here...
    return m_[i_*N*P + j_*P + k_];
}

template<typename T>
inline const T& get_elem(const vector<T>& m_, size_t i_, size_t j_, size_t k_)
{
    // check indexes here...
    return m_[i_*N*P + j_*P + k_];
}

最后,可以创建一个向量并将其编入索引:

Vector array3d(M*N*P, 0);            // create 3-d array containing M*N*P zero ints
set_elem(array3d, 0, 0, 1) = 5;      // array3d[0][0][1] = 5
auto n = get_elem(array3d, 0, 0, 1); // n = 5

在初始化时定义矢量大小提供optimal performance。此解决方案已从this answer修改。可以使用单个向量来重载函数以支持不同的维度。该解决方案的缺点是M,N,P参数被隐式传递给get和set函数。这可以通过在类中实现解决方案来解决,如Pixelchemist所述。