如何将数组从行顺序重写为列顺序?

时间:2010-01-30 13:58:44

标签: c++ c

我有这个双for循环,其中我有行顺序和列顺序数组索引,这应该对性能不利。

  for (int row = 0; row < height; row++) {
    for (int col = 0; col < width; col++) {

      /* Column-major order */
      d = array_a[col*height +row];

      if (d < 0) { d = 0; }

      /* Row-major order */
      /* Map from x=0,y=0 at buttom left corner to
         0,0 at top left corner */
      array_b[width*(height-1 -row) + col] = d;

    }
  }

是否有关于如何从一个重写到另一个的方法/方法?

当我尝试将最后一个重写为列顺序时,数据会变得偏斜。不能改写吗?

桑德拉

5 个答案:

答案 0 :(得分:11)

由于问题标记为C ++,我将提供一个答案,显示如何使用Boost.Multiarray访问/操作列主矩阵(对于遇到类似问题的其他人可能会有用)。我认为Boost是C ++标准库的扩展。如果你不喜欢/使用Boost,请随意忽略这个答案。 : - )

#include <algorithm>
#include <iostream>
#include <boost/multi_array.hpp>

// Prints the contents of a matrix to standard output
template <class M> void printMatrix(const M& matrix)
{
    int height = matrix.shape()[0];
    int width = matrix.shape()[1];
    for (int row=0; row<height; ++row)
    {
        for (int col=0; col<width; ++col)
        {
            std::cout << matrix[row][col] << " ";
        }
        std::cout << "\n";
    }
}

int main()
{
    // Source matrix data is in column-major format in memory,
    // with data starting at bottom-left corner.
    double data[] =
    {
        3, 7, 11,
        2, 6, 10,
        1, 5, 9,
        0, 4, 8
    };
    int width=4, height=3;

    // Store rows, then columns (column-major)
    int ordering[] = {0,1};

    // Store rows in descending order (flips Y axis)
    bool ascending[] = {true,false};

    // Create a multi_array that references the existing data,
    // with custom storage specifications.
    typedef boost::multi_array_ref<double, 2> Matrix;
    typedef boost::general_storage_order<2> Storage;
    Matrix matrix(
        data,
        boost::extents[height][width],
        Storage(ordering, ascending)
    );

    // Access source data as if it's row major
    printMatrix(matrix);
    std::cout << "\n";

    // Transpose source data to an actual row-major matrix
    // boost::multi_array is row-major by default
    boost::multi_array<double, 2> matrix2(boost::extents[height][width]);
    std::copy(matrix.begin(), matrix.end(), matrix2.begin());
    printMatrix(matrix2);
}

输出:

0 1 2 3
4 5 6 7
8 9 10 11

0 1 2 3
4 5 6 7
8 9 10 11

正如您所看到的,您可以将源数据保留为列主格式,并使用boost::multi_array_ref和自定义存储规范来直接操作数据(就好像它是行主要的)使用{{ 1}}符号。

如果矩阵通常以行主方式遍历,那么将它转换为实际的行主矩阵可能会更好,如我的示例的最后一部分所示。

答案 1 :(得分:4)

这永远不会非常快,因为你可能会有很多缓存未命中,你要么必须以大音调或另一个步进到一个矩阵,那么就没有逃避。这里的问题是计算机喜欢连续的内存访问是靠近在一起的,在你的算法中不是这样的情况,由于col 高度项,array_a的索引一次跳过高度元素。要解决这个问题,你可以在循环中切换,但是你在array_b中的宽度(height-1 -row)项有同样的问题。

你可以重写其中一个数组以匹配另一个数组的顺序,但是你会在重写的代码中遇到完全相同的问题,所以这取决于你是否需要做更多这样的事情一旦使用相同的数据,如果你这样做,那么首先重写一个像Poita_描述的矩阵是有意义的,否则你最好保持算法不变。

答案 2 :(得分:3)

所以你想要改变:

0  1  2  3
4  5  6  7
8  9  10 11

0  3  6  9
1  4  7  10
2  5  8  11

尝试

for (int i = 0; i < width; ++i)
  for (int j = 0; j < height; ++j)
    array_b[ i * height + j ] = array_a[ j * width + i ];

答案 3 :(得分:3)

如果交换行orrdering很常见,那么编写自己的数组类。

实际上,数据实际上不必移动访问数据的接口需要知道如何访问数据。

#include <vector>
class Matrix
{
  public:
    Matrix(int width,int height)
        :data(width,std::vector<int>(height))
        ,rowOrder(true)
    {
    }
    int& operator()(int x,int y)
    {
        return at(x,y);
    }
    int const& operator()(int x,int y) const
    {
        return const_cast<Matrix&>(*this).at(x,y);
    }

    void switchRowOrder()
    {
        rowOrder = !rowOrder;
    }

  private:
    int& at(int x,int y)
    {
        int& result = (rowOrder)
                            ?data[x][y]  // row Order Access
                            :data[y][x]; // col Order Access

        // Note there is no code to swap around the content of the data internally.
        return result;
    }

    std::vector<std::vector<int> >  data;
    bool rowOrder;
};

答案 4 :(得分:2)

这不是导致数据偏差的原因吗?所有负值都被清零:

if (d < 0) { d = 0; }