我需要表示一个2D场(轴x,y),我遇到了一个问题:我应该使用一维数组还是2D数组?
我可以想象,重新计算1D数组的索引(y + x * n)可能比使用2D数组(x,y)慢,但我可以想象1D可能在CPU缓存中。
我做了一些谷歌搜索,但只发现了关于静态数组的页面(并说明1D和2D基本相同)。但我的阵列必须是我的动态。
那么,什么是
动态1D阵列还是动态2D阵列?
谢谢:)
答案 0 :(得分:17)
除非你在讨论静态数组, 1D更快。
这是一维数组(std::vector<T>
)的内存布局:
+---+---+---+---+---+---+---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+---+---+---+
动态二维数组(std::vector<std::vector<T>>
)的情况也是如此:
+---+---+---+
| * | * | * |
+-|-+-|-+-|-+
| | V
| | +---+---+---+
| | | | | |
| | +---+---+---+
| V
| +---+---+---+
| | | | |
| +---+---+---+
V
+---+---+---+
| | | |
+---+---+---+
显然,2D情况会丢失缓存局部性并使用更多内存。它还引入了一个额外的间接(因此引入了一个额外的指针),但是第一个数组有计算索引的开销,所以它们或多或少都有。
答案 1 :(得分:8)
尺寸:两者都需要相同的内存量。
速度:您可以假设没有速度差异,因为这两个阵列的内存应该是连续的( 整个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所述。