这可能是一个基本问题。我是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 ++代码并逐个读取元素知道它的索引,以便我避免将整个矩阵存储在内存中吗?
非常感谢你!
答案 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
的元素的坐标,但应该很容易将这些坐标以及位置上的值存储到合适的容器中。