从文本文件中创建一个二维数组

我正在使用稀疏矩阵,并给我一个像这样的文本文件:

0 3 1.2 2 5 3.2 3 0 2.1 3 5 4.2 4 5 2.2 0 0 5.2 

基本上它的工作方式是位置[0] [3]上的数字1.2和未提及的matriz的元素保持为0,所以在这种情况下它应该如下所示:

 5.2 0 0 1.2 0 0 0 0 0 0 0 0 0 0 0 0 0 3.2 2.1 0 0 0 0 4.2 0 0 0 0 0 2.2 

OP在评论中写道:

我很抱歉,但是我的老师刚刚澄清了一切……事实certificate,对于每一行,第一个数字是行,第二个是列,第三个是元素。我上面的例子, 1.2必须去在[0][3]的位置。 矩阵不必是方形的。

这使每件事都不同。 如果您不知道矩阵的尺寸,则必须首先读取所有内容,然后计算矩阵尺寸,为矩阵分配空间,然后用值填充它。

我这样做:

 #include  #include  #define BLOCK 1024 struct matrix_info { int col; int row; double val; }; void free_matrix(double **matrix, size_t rows) { if(matrix == NULL) return; for(size_t i = 0; i < rows; ++i) free(matrix[i]); free(matrix); } double **readmatrix(const char *fname, size_t *rows, size_t *cols) { if(fname == NULL || rows == NULL || cols == NULL) return NULL; double **matrix = NULL; struct matrix_info *info = NULL; size_t mi_idx = 0; // matrix info index size_t mi_size = 0; FILE *fp = fopen(fname, "r"); if(fp == NULL) { fprintf(stderr, "Cannot open %s\n", fname); return NULL; } *rows = 0; *cols = 0; for(;;) { if(mi_idx >= mi_size) { struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info); if(tmp == NULL) { fprintf(stderr, "not enough memory\n"); free(info); fclose(fp); return NULL; } info = tmp; mi_size += BLOCK; } int ret = fscanf(fp, "%d %d %lf", &info[mi_idx].row, &info[mi_idx].col, &info[mi_idx].val); if(ret == EOF) break; // end of file reached if(ret != 3) { fprintf(stderr, "Error parsing matrix\n"); free(info); fclose(fp); return NULL; } if(*rows < info[mi_idx].row) *rows = info[mi_idx].row; if(*cols < info[mi_idx].col) *cols = info[mi_idx].col; mi_idx++; } fclose(fp); // mi_idx is now the length of info // *cols and *rows have the largest index // for the matrix, hence the dimension is (rows + 1) x (cols + 1) (*cols)++; (*rows)++; // allocating memory matrix = calloc(*rows, sizeof *matrix); if(matrix == NULL) { fprintf(stderr, "Not enough memory\n"); free(info); return NULL; } for(size_t i = 0; i < *rows; ++i) { matrix[i] = calloc(*cols, sizeof **matrix); if(matrix[i] == NULL) { fprintf(stderr, "Not enough memory\n"); free(info); free_matrix(matrix, *rows); return NULL; } } // populating matrix for(size_t i = 0; i < mi_idx; ++i) { int r,c; r = info[i].row; c = info[i].col; matrix[r][c] = info[i].val; } free(info); return matrix; } int main(void) { const char *fn = "/tmp/matrix.txt"; size_t rows, cols; double **matrix = readmatrix(fn, &rows, &cols); if(matrix == NULL) return 1; for(size_t i = 0; i < rows; ++i) { for(size_t j = 0; j < cols; ++j) printf("%0.3f ", matrix[i][j]); puts(""); } free_matrix(matrix, rows); return 0; } 

输出是(对于包含样本数据的文件)

 5.200 0.000 0.000 1.200 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 3.200 2.100 0.000 0.000 0.000 0.000 4.200 0.000 0.000 0.000 0.000 0.000 2.200 

所以快速解释我在做什么:

我读取文件并在动态分配的数组中存储有关列,行和值的信息。 此信息存储在struct matrix_info *info

我的想法是我读取每一行并提取三个值。 当我读取文件时,我还存储了列和行的最大索引

  ... if(*rows < info[mi_idx].row) *rows = info[mi_idx].row; if(*cols < info[mi_idx].col) *cols = info[mi_idx].col; ... 

所以当读取文件时,我知道矩阵的尺寸。 现在所有带有行和列的值都存储在info数组中,因此下一步是为矩阵分配内存并根据info[i]条目填充值。

 for(size_t i = 0; i < mi_idx; ++i) { int r,c; r = info[i].row; c = info[i].col; matrix[r][c] = info[i].val; } 

最后我释放内存以获取info并返回矩阵。

另一个有趣的部分是:

  if(mi_idx >= mi_size) { struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info); if(tmp == NULL) { fprintf(stderr, "not enough memory\n"); free(info); fclose(fp); return NULL; } info = tmp; mi_size += BLOCK; } 

因为你提到你对矩阵唯一了解的是它可能包含多达10000个元素,那么输入文件可能会非常大。 我没有为每个循环上的info元素重新分配内存,而是一次分配1024个( BLOCKinfo元素的块。 因此,一旦块已满,则分配下一个块,依此类推。 所以我每1024次迭代只调用realloc

你需要先使用:

 float* sparseMatrix = malloc(sizeof(float) * 10000); 

你开始读取文件,在读取第一行之后你知道colums的nomber,行数是读取的行数。 如果需要,可以减少矩阵。

 free(sparseMatrix ); sparseMatrix = malloc(sizeof(float) * nbRow*nbColum); 

您根本没有足够的信息来构建适当的矩阵。 在你引用的案例中,你知道你有至少 5行和至少 6列,但你不知道你的矩阵中有多少行m和列n 。 所以对于你的输入:

 0 3 1.2
 2 5 3.2
 3 0 2.1
 3 5 4.2
 4 5 2.2
 0 0 5.2

您可以使用5×6矩阵:

 5.2 0.0 0.0 1.2 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 3.2
 2.1 0.0 0.0 0.0 0.0 4.2
 0.0 0.0 0.0 0.0 0.0 2.2

或者您可以使用10×6矩阵:

 5.2 0.0 0.0 1.2 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 3.2
 2.1 0.0 0.0 0.0 0.0 4.2
 0.0 0.0 0.0 0.0 0.0 2.2
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0
 0.0 0.0 0.0 0.0 0.0 0.0

这种模糊性是一个问题,因为第一个矩阵与第二个矩阵大不相同。

而且, 稀疏矩阵的点对于存储器和/或处理时间是有效的。 如果您分配了m行和n列的完整数组,那么您将拥有密集矩阵表示。

除非你先自己完全阅读文件,否则没有真正的方法可以知道文件中的内容。

由于您知道将有最多10k个元素,因此您可以先静态分配该大小的数组,然后将数字加载到解析EOF中。

 float sparseMatrix[10000]; 

它只是意味着您的程序将始终为10k元素分配空间,而不管数组中实际有多少元素。 如果你假设每个元素占用4个字节,那么你将只使用~40kB的内存。 这可能是最简单的解决方案。

另一种选择是完全读取文件,找出所需的大小,并动态分配该大小,然后在填充元素时再次读取整个文件。

 // Assume numberOfElements was determined by reading through the file first float* sparseMatrix = malloc(sizeof(float) * numberOfElements); 

虽然这种方法将使用更少的内存,但它需要两次完整的文件读取+调用malloc的开销。

您可以测量行数和列数,然后定义2d数组。 当然,这会增加时间复杂度! 如果您不关心内存的大小,可以使用最大列和行定义数组! 所以你应该选择大时间复杂度和大内存大小。