C++ 一维或二维阵列,什么';快一点?

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数

我需要表示二维场(轴x,y),我面临一个问题:我应该使用一维数组还是二维数组

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

我在谷歌上搜索了一下,但只找到了关于静态数组的页面(并指出1D和2D基本相同)。但我的数组必须是动态的

那么,这是什么

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

    1D和2D静态阵列
    • 大小:两者都需要相同的内存量

    • 速度:您可以假设不会有速度差异,因为这两个数组的内存应该是连续的(即 整个2D数组应该在内存中显示为一个块,而不是一个数组 一堆块散布在内存中)。(这可能是编译器 不过,这要视情况而定。)

    1D和2D动态阵列
    • 大小:二维数组需要比一维数组多一点内存,因为二维数组中需要指针指向分配的一维数组集。(当我们谈论真正的大阵列时,这个微小的比特只是微小的。对于小阵列,相对而言,这个微小的比特可能相当大。)

    • 速度:1D数组可能比2D数组快,因为2D数组的内存不连续,因此缓存未命中将成为一个问题


    使用最有效、最符合逻辑的方法,如果遇到速度问题,则重构。

    1D和2D静态数组
    • 大小:两者都需要相同的内存量

    • 速度:您可以假设不会有速度差异,因为这两个数组的内存应该是连续的(即 整个2D数组应该在内存中显示为一个块,而不是一个数组 一堆块散布在内存中)。(这可能是编译器 不过,这要视情况而定。)

    1D和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