如何从文件中逐个读取矩阵元素

时间:2013-09-18 21:20:10

标签: c++ file matrix

这可能是一个基本问题。我是C ++的新手,我想实现一个可能不适合内存的巨大随机矩阵。所以我想也许我应该将它写入一个文件并在流中逐个元素地读取。

如果元素小于阈值,我想检查的是。如果是,则将元素(i,j)的索引推入stl向量中进行存储,如果不是,则转到下一个元素。

基本上我需要几行将矩阵AJM写入matrix.dat,然后将其元素读取为:

for (int i = 0; i < ROWS; i++)
{
    for (int j = 0; j < COLS; j++)
    {
        currentElement = "read AJM[i][j] from matrix.txt";
    } 
}

所以“从matrix.txt读取AJM [i] [j]”对我来说并不清楚,我想这是通过将文件指针迭代到i和j给出的某个特定位置来完成的,并指定要读取的字节数,对吗?

你能告诉我编写matrix.dat的C ++代码并逐个读取元素知道它的索引,以便我避免将整个矩阵存储在内存中吗?

非常感谢你!

3 个答案:

答案 0 :(得分:4)

你可能在这里重新发明轮子。如果矩阵是密集的,则基本上有两种选择:列主要顺序(对于Fortran兼容性)或行主要顺序(对于C多维数组兼容性)。如果矩阵是稀疏的,那么有一些标准格式可以从中选择最合适的(即三对角矩阵的选择不同于“一般”稀疏矩阵),CSR / CSC可能是最普遍的“非常一般” “稀疏矩阵表示。您选择的内存中表示将在很大程度上通知基于磁盘的表示。我的建议是:找到并使用一个能够满足您需求的库,而不是重新发明轮子。

你已经回答说矩阵密集,我有点/有点想回答我认为你应该问的问题,而不是你实际问过的问题。如果你真的有一个巨大的矩阵(比如十亿个元素)存储为<​​em> text ,你将会有一个非常非常糟糕的时间,所以我要去假设矩阵存储为双精度数,以使生活更轻松。

虽然还有其他可能性,但密集矩阵基本上有两个简单的磁盘表示:行主要顺序和列主要顺序。选择其中之一后,有两个选择来获取索引i,j并从文件中检索该值,知道矩阵维度。假设矩阵维度为m(行)n(列),则对应于元素i,j的矩阵开头的偏移量为(对于行主要顺序):< / p>

offset = i*n + j

或(对于列主要订单):

offset = j*m + i

假设矩阵元素都是双精度数,那么您可以通过此偏移seek()进入文件,对于行主要顺序执行类似(其中mfs附加std::ifstream到矩阵文件):

double element;
mfs.seekg( (i*n+j)*sizeof(double) );
mfs.read( reinterpret_cast<char*>(&element), sizeof(double) );

或者,在类似POSIX的系统上,您可以使用mmap()将矩阵文件映射到内存中,并使用相同的基本原理来计算适当的偏移量。

答案 1 :(得分:0)

如果您想使用文件,则必须决定所存储数据的编码。

天真的实现是按顺序存储每个元素,在下一行之前按顺序执行每一行(或列)。

无论您使用什么编码,如果它不适合内存,您将不得不使用允许重新定位以找到正确元素的文件句柄。具体如何工作取决于您从文件中加载的内容。

大多数情况下,此操作称为Seek或一些微小变化。

答案 2 :(得分:0)

如何读取矩阵取决于矩阵的写入方式。就个人而言,我首先要通过指定矩阵的宽度和高度来编写矩阵,然后将每一行写成一行。为简单起见,我将矩阵写为文本文件,例如,如下所示:

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

阅读这样的矩阵非常简单:

int rows(0), columns(0);
if (in >> rows >> columns) {
    std::vector<std::vector<double>> matrix(rows);
    for (int r(0); in && r != rows; ++r) {
        std::copy_n(std::istream_iterator<double>(in), columns,
                    std::back_inserter(matrix[r]));
    }
}
if (!in) {
    std::cout << "ERROR: failed to read matrix\n";
}

显然,如果你已经有了矩阵结构,你可以使用类似的方法直接填充矩阵的各个元素。要仅存储某些元素或它们的坐标,您可以通过有条件地使用相应坐标调用方法的内容替换std::copy_n()函数,例如,

template <typename InIt, typename Predicate, typename Fun>
void filter_n(InIt it, int n, Predicate pred, Fun fun) {
    for (int i = 0; i != n; ++i, ++it) {
        if (pred(*it)) {
            fun(*it, i);
        }
    }
}

...然后用适当的调用此函数替换std::copy_n(),例如,

    filter_n(std::istream_iterator<double>(in), columns,
             [threshold](double d){ return d < threshold; },
             [r](double, int c) { std::cout << "(" << r << ", " << c << ")\n"; });

这只会打印小于threshold的元素的坐标,但应该很容易将这些坐标以及位置上的值存储到合适的容器中。