【问题标题】:Making a 2d array from a text file从文本文件制作二维数组
【发布时间】:2018-04-18 21:38:19
【问题描述】:

我正在处理一个稀疏矩阵,我给了一个这样的文本文件:

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

基本上它的工作方式是数字 1.2 在位置 [0] [3] 上,而未提及的矩阵元素保持在 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

【问题讨论】:

  • 当你说你不知道大小时,那是只适用于行还是也适用于列?
  • 1) 为 10000 个元素分配足够的空间 2) 读取文件 3) 重新分配到更小的大小。
  • 各行是什么意思。矩阵也是正方形吗?找到这些问题的答案后,您将如何着手解决问题?
  • Pablo 我不知道行数或 comuns 的数量,所以我不能在我的代码开头声明它们的值
  • 好的,所以你也不知道列数。所有行的行数都相同吗?

标签: c multidimensional-array text-files


【解决方案1】:

OP 在 cmets 中写道:

很抱歉,我的老师刚刚澄清了一切......事实证明,对于每一行,第一个数字是行,第二个是列,第三个是元素。上面的例子,@ 987654321@ 必须进入[0][3] 的位置。矩阵不必是方阵。

这让每一件事都变得不同。如果你不知道尺寸 矩阵,那么你必须先阅读所有内容,然后计算矩阵 维度,为矩阵分配空间,然后用值填充它。

我会这样做:

#include <stdio.h>
#include <stdlib.h>

#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 个 (BLOCK) info 个元素的块。因此,一旦一个块已满, 下一个块被分配等等。所以我每 1024 次才打电话给realloc 迭代。

【讨论】:

  • 我理解你在做什么@Pablo,但以这种方式表示稀疏矩阵确实没有意义 - 即:作为密集矩阵。我怀疑 OP 仍然缺少作业中的某些内容。
  • @MFisherKDX 没有正确的规范,必须进行猜测。我决定不对矩阵的维度进行任何猜测,因此我需要先阅读所有行,然后才能确定矩阵的大小。这是更通用的方法。当然,我知道矩阵的上界(或矩阵的其他属性),可以简化代码。而且我们不知道 OP 的矩阵是否是稀疏矩阵。输入文件可能非常大并且包含所有矩阵索引的值,OP 可能选择只显示几行。
  • 是的,但是 OP 的问题陈述的第一行是:我正在使用一个稀疏矩阵,并且我给了一个像这样的文本文件:。所以我假设 OP 确实有一个稀疏矩阵。
  • 谢谢!在这种情况下,我从终端调用文件(如:/.project )所以我认为我必须在主函数中读取并制作矩阵
  • @MuchoG 来自我的代码,你必须将main 更改为int main(int argc, char **argv),然后调用readmatrix(argv[1], &amp;rows, &amp;cols);。当然别忘了检查argv[1] 不是NULL
【解决方案2】:

你需要先使用:

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

您开始读取文件,在第一行读取后您知道列数,行数是读取的行数。如果你愿意,你可以减少矩阵。

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

【讨论】:

  • 这将破坏稀疏矩阵并且读取的值将消失。您必须使用realloc 来减少分配的内存量。
【解决方案3】:

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

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

你可以有一个 5x6 矩阵:

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

或者你可以有一个 10x6 矩阵:

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

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

此外,sparse matrix 的重点是提高内存和/或处理时间的效率。如果您分配一个完整的 m 行和 n 列数组,那么您将获得 密集矩阵 表示。

【讨论】:

  • 在这种情况下,由于 2.2 位于位置 [4][5] 并且在更大的行或列中没有元素,因此矩阵应该有 4 行和 5 列。如果它是位置 [5] [5] 中不为 0 的元素,则矩阵应该有 5 行和 5 列
【解决方案4】:

除非您自己完全阅读文件,否则无法真正了解文件中的内容。

由于您知道最多会有 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 的开销。

【讨论】:

  • 我认为稀疏矩阵不应该以这种方式表示。它应该以节省内存和/或处理时间的方式表示。
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    相关资源
    最近更新 更多