C++ 一维或二维阵列,什么';快一点?
我需要表示二维场(轴x,y),我面临一个问题:我应该使用一维数组还是二维数组 我可以想象,重新计算1D数组(y+x*n)的索引可能比使用2D数组(x,y)慢,但我可以想象1D可能在CPU缓存中 我在谷歌上搜索了一下,但只找到了关于静态数组的页面(并指出1D和2D基本相同)。但我的数组必须是动态的 那么,这是什么C++ 一维或二维阵列,什么';快一点?,c++,c,arrays,C++,C,Arrays,我需要表示二维场(轴x,y),我面临一个问题:我应该使用一维数组还是二维数组 我可以想象,重新计算1D数组(y+x*n)的索引可能比使用2D数组(x,y)慢,但我可以想象1D可能在CPU缓存中 我在谷歌上搜索了一下,但只找到了关于静态数组的页面(并指出1D和2D基本相同)。但我的数组必须是动态的 那么,这是什么 更快 较小(RAM) 动态1D阵列还是动态2D阵列?1D和2D静态阵列 大小:两者都需要相同的内存量 速度:您可以假设不会有速度差异,因为这两个数组的内存应该是连续的(即 整个2D数
- 大小:两者都需要相同的内存量
- 速度:您可以假设不会有速度差异,因为这两个数组的内存应该是连续的(即 整个2D数组应该在内存中显示为一个块,而不是一个数组 一堆块散布在内存中)。(这可能是编译器 不过,这要视情况而定。)
- 大小:二维数组需要比一维数组多一点内存,因为二维数组中需要指针指向分配的一维数组集。(当我们谈论真正的大阵列时,这个微小的比特只是微小的。对于小阵列,相对而言,这个微小的比特可能相当大。)
- 速度:1D数组可能比2D数组快,因为2D数组的内存不连续,因此缓存未命中将成为一个问题
使用最有效、最符合逻辑的方法,如果遇到速度问题,则重构。1D和2D静态数组
- 大小:两者都需要相同的内存量
- 速度:您可以假设不会有速度差异,因为这两个数组的内存应该是连续的(即 整个2D数组应该在内存中显示为一个块,而不是一个数组 一堆块散布在内存中)。(这可能是编译器 不过,这要视情况而定。)
- 大小:二维数组需要比一维数组多一点内存,因为二维数组中需要指针指向分配的一维数组集。(当我们谈论真正的大阵列时,这个微小的比特只是微小的。对于小阵列,相对而言,这个微小的比特可能相当大。)
- 速度:1D数组可能比2D数组快,因为2D数组的内存不连续,因此缓存未命中将成为一个问题
使用最符合逻辑的方法,如果遇到速度问题,则重构。除非您谈论的是静态数组,1D速度更快 这是一维数组(
std::vector
)的内存布局:
对于动态2D数组(std::vector
)也是如此:
显然,2D案例会丢失缓存位置并使用更多内存。它还引入了一个额外的间接寻址(因此需要跟随一个额外的指针),但第一个数组有计算索引的开销,因此这些索引或多或少都是平衡的。除非您谈论的是静态数组,1D更快 这是一维数组(
std::vector
)的内存布局:
对于动态2D数组(std::vector
)也是如此:
显然,2D案例会丢失缓存位置并使用更多内存。它还引入了一个额外的间接寻址(因此需要跟随一个额外的指针),但第一个数组有计算索引的开销,因此这些索引或多或少都是一致的。这实际上取决于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.
}
inta[200]、b[10][20]、*c[10]、*d[10];
对于(ii=0;ii<10;++ii)
{
c[ii]=&b[ii][0];
d[i2] =(int *)Maloc(20×sieof(int));(+)只用于C++。
}
这里有3种实现:b、c和d
访问
b[x][y]
或a[x*20+y]
不会有太大的区别,因为一个是您进行计算,另一个是编译器为您进行计算c[x][y]
和d[x][y]
速度较慢,因为机器必须找到c[x]
指向的地址,然后从那里访问yth元素。这不是一个简单的计算。在一些机器上(例如AS400,它有36字节(不是位)指针),指针访问速度非常慢。这完全取决于所使用的体系结构。在x86类型的体系结构上,a和b的速度相同,c和d的速度比b慢。这实际上取决于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.
}
inta[200]、b[10][20]、*c[10]、*d[10];
对于(ii=0;ii<10;++ii)
{
c[ii]=&b[ii][0];
d[i2] =(int *)Maloc(20×sieof(int));(+)只用于C++。
}
这里有3种实现:b、c和d
访问b[x][y]
或a[x*20+y]
不会有太大的区别,因为一个是您进行计算,另一个是编译器为您进行计算c[x][y]
和d[x][y]
速度较慢,因为机器必须找到c[x]
指向的地址,然后从那里访问yth元素。这不是一个简单的计算。在一些机器上(例如AS400,它有36字节(不是位)指针),指针访问速度非常慢。这完全取决于所使用的体系结构。在x86类型的体系结构上,a和b的速度相同,c和d的速度比b慢。tl;博士:你可能应该使用一维的方法。
注意:在比较动态1d或动态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.
}
int get_2d (int **p, int r, int c) { return p[r][c]; }
int get_1d (int *p, int r, int c) { return p[c + C*r]; }
?get_1d@@YAHPAHII@Z PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR _c$[ebp]
lea eax, DWORD PTR [eax+edx*4]
mov eax, DWORD PTR [ecx+eax*4]
pop ebp
ret 0
?get_2d@@YAHPAPAHII@Z PROC
push ebp
mov ebp, esp
mov ecx, DWORD PTR [ecx+edx*4]
mov eax, DWORD PTR _c$[ebp]
mov eax, DWORD PTR [ecx+eax*4]
pop ebp
ret 0
int main (void)
{
// allocate memory for 4x4 integers; quick & dirty
int ** p = new int*[4];
for (size_t i=0; i<4; ++i) p[i] = new int[4];
// do some stuff here, using p[x][y]
// deallocate memory
for (size_t i=0; i<4; ++i) delete[] p[i];
delete[] p;
}
// allocate memory for 4x4 integers; quick & dirty
size_t const N = 4;
// we don't need try for this allocation
// if it fails there is no leak
int ** p = new int*[N];
size_t allocs(0U);
try
{ // try block doing further allocations
for (size_t i=0; i<N; ++i)
{
p[i] = new int[4]; // allocate
++allocs; // advance counter if no exception occured
}
}
catch (std::bad_alloc & be)
{ // if an exception occurs we need to free out memory
for (size_t i=0; i<allocs; ++i) delete[] p[i]; // free all alloced p[i]s
delete[] p; // free p
throw; // rethrow bad_alloc
}
/*
do some stuff here, using p[x][y]
*/
// deallocate memory accoding to the number of allocations
for (size_t i=0; i<allocs; ++i) delete[] p[i];
delete[] p;
#include <vector>
#include <algorithm>
#include <iterator>
#include <utility>
namespace matrices
{
template<class T>
class simple
{
public:
// misc types
using data_type = std::vector<T>;
using value_type = typename std::vector<T>::value_type;
using size_type = typename std::vector<T>::size_type;
// ref
using reference = typename std::vector<T>::reference;
using const_reference = typename std::vector<T>::const_reference;
// iter
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
// reverse iter
using reverse_iterator = typename std::vector<T>::reverse_iterator;
using const_reverse_iterator = typename std::vector<T>::const_reverse_iterator;
// empty construction
simple() = default;
// default-insert rows*cols values
simple(size_type rows, size_type cols)
: m_rows(rows), m_cols(cols), m_data(rows*cols)
{}
// copy initialized matrix rows*cols
simple(size_type rows, size_type cols, const_reference val)
: m_rows(rows), m_cols(cols), m_data(rows*cols, val)
{}
// 1d-iterators
iterator begin() { return m_data.begin(); }
iterator end() { return m_data.end(); }
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
const_iterator cbegin() const { return m_data.cbegin(); }
const_iterator cend() const { return m_data.cend(); }
reverse_iterator rbegin() { return m_data.rbegin(); }
reverse_iterator rend() { return m_data.rend(); }
const_reverse_iterator rbegin() const { return m_data.rbegin(); }
const_reverse_iterator rend() const { return m_data.rend(); }
const_reverse_iterator crbegin() const { return m_data.crbegin(); }
const_reverse_iterator crend() const { return m_data.crend(); }
// element access (row major indexation)
reference operator() (size_type const row,
size_type const column)
{
return m_data[m_cols*row + column];
}
const_reference operator() (size_type const row,
size_type const column) const
{
return m_data[m_cols*row + column];
}
reference at() (size_type const row, size_type const column)
{
return m_data.at(m_cols*row + column);
}
const_reference at() (size_type const row, size_type const column) const
{
return m_data.at(m_cols*row + column);
}
// resizing
void resize(size_type new_rows, size_type new_cols)
{
// new matrix new_rows times new_cols
simple tmp(new_rows, new_cols);
// select smaller row and col size
auto mc = std::min(m_cols, new_cols);
auto mr = std::min(m_rows, new_rows);
for (size_type i(0U); i < mr; ++i)
{
// iterators to begin of rows
auto row = begin() + i*m_cols;
auto tmp_row = tmp.begin() + i*new_cols;
// move mc elements to tmp
std::move(row, row + mc, tmp_row);
}
// move assignment to this
*this = std::move(tmp);
}
// size and capacity
size_type size() const { return m_data.size(); }
size_type max_size() const { return m_data.max_size(); }
bool empty() const { return m_data.empty(); }
// dimensionality
size_type rows() const { return m_rows; }
size_type cols() const { return m_cols; }
// data swapping
void swap(simple &rhs)
{
using std::swap;
m_data.swap(rhs.m_data);
swap(m_rows, rhs.m_rows);
swap(m_cols, rhs.m_cols);
}
private:
// content
size_type m_rows{ 0u };
size_type m_cols{ 0u };
data_type m_data{};
};
template<class T>
void swap(simple<T> & lhs, simple<T> & rhs)
{
lhs.swap(rhs);
}
template<class T>
bool operator== (simple<T> const &a, simple<T> const &b)
{
if (a.rows() != b.rows() || a.cols() != b.cols())
{
return false;
}
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}
template<class T>
bool operator!= (simple<T> const &a, simple<T> const &b)
{
return !(a == b);
}
}
int (*p)[num_columns] = malloc(num_rows * sizeof *p);
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