【问题标题】:Read from file fast快速读取文件
【发布时间】:2016-01-24 04:04:33
【问题描述】:

我有一个 txt 文件,其中包含 2 个图形和以下格式的顶点数:

6
0 1 0 1 0 0
1 0 1 0 0 1
0 1 0 1 0 0
1 0 1 0 1 0
0 0 0 1 0 1
0 1 0 0 1 0
0 1 0 0 1 0
1 0 1 0 0 0
0 1 0 1 0 1
0 0 1 0 1 0
1 0 0 1 0 1
0 0 1 0 1 0

矩阵表示顶点邻接。如果两个顶点相邻,则它们的对为 1。 尽管这些图在视觉上没有分开,但第二张图在第一张图的第 6 行之后开始。 每个图可以有很多顶点,比如 5000 个,并且它们的大小相同(图)。 我编写了一个算法来检查两个图是否同构,我注意到读取这些图需要 8 秒,而实际算法需要 2.5 秒(对于 5000 个顶点)。 由于我的目标是优化程序的整体速度,我想知道我是否可以改进(在速度方面)我当前从文件读取的代码:

FILE* file = fopen ("input.txt", "r");
fscanf (file, "%d", &i);
int n = i;
while (!feof (file))
{  
    fscanf (file, "%d", &i); 
    if (j < (n*n)) {  // first graph
        if (i==1) {
            adj_1[j/n][v_rank_1[j/n]] = j - (j/n)*n; // add the vertice to the adjacents of the current vertice
            v_rank_1[j/n] += 1;
        }
    }
    else if (j>=(n*n)) {   // second graph
        if (i==1) {
            adj_2[(j-(n*n))/n][v_rank_2[(j-(n*n))/n]] = (j-(n*n)) - ((j-(n*n))/n)*n; // add the vertice to the adjacents of the current vertice
            v_rank_2[(j-(n*n))/n] += 1;
        }
    }
    j++;
}
fclose (file);

adj_* 表保存了一个顶点的相邻顶点的索引

v_rank_* 表保存与顶点相邻的顶点数

重要的是我从图表中获取此信息,并且仅获取此信息。

【问题讨论】:

  • This answer 可能相关并且您可能感兴趣。
  • 旁白:我看到您在尝试读取文件之前正在使用feof。这是错误的,请参阅stackoverflow.com/questions/5431941/… 并阅读feof 的手册页。我建议将循环更改为while (1 != fscanf (file, "%d", &amp;i))
  • @WeatherVane 哦,很抱歉,我没有提供之前打开文件的代码并读取了顶点数(代码中很早)。现在添加了
  • 数字是否保证都是个位数?
  • @Crone 您添加的代码不会原谅使用while (!feof())。这是完全错误的,虽然离题了。

标签: c input graph text-files


【解决方案1】:

第一个优化是一次性读取内存中的整个文件。在循环中访问内存将比调用 fread 更快。

第二个优化是减少算术运算,即使这意味着更多的代码。

第三个优化是将文件中的数据视为字符以避免整数转换。

结果可能是:

// bulk read file into memory
fseek(file, 0, SEEK_END);
long fsize = ftell(file);
fseek(file, 0, SEEK_SET);
char *memFile = malloc(fsize + 1);
if (memFile == NULL) return; // not enough memory !! Handle it as you wish
fscanf(file, "%d", &n);
fread(memFile, fsize, 1, file);
fclose(file);
memfile[fsize] = 0;

// more code but less arythmetic operations
int lig, col;
char *mem = memFile, c;
for (int lig = 0; lig < n; lig++) { // first graph
    for (int col = 0; col < n; col++) {
        for (;;)
        {
            c = *mem;
            if (c == 0) break;
            mem++;
            if (c == '1') {
                adj_1[lig][v_rank_1[lig]++] = col; // add the vertice to the adjacents of the current vertice
                k++; // ??
                break;
            }
            if (c == '0') break;
        }

    }
}
for (int lig = 0; lig < n; lig++) { // second graph
    for (int col = 0; col < n; col++) {
            c = *mem;
            if (c == 0) break;
            mem++;
            if (c == '1') {
                adj_2[(lig][v_rank_2[lig]++] = col; // add the vertice to the adjacents of the current vertice
                l++;  // ??
                break;
            }
            if (c == '0') break;
        }
    }
}
free(memFile);

备注:你没有提到变量kl

【讨论】:

  • 神圣@#!与之前的 8.0s-8.5s 相比,此方法运行时间为 0.6 秒。 k 和 l 是不再使用的旧代码。
  • 摆脱这一点的是,您正在学习一些算法和方法的权衡。您的原始方法使用的 RAM 非常少,但执行速度很慢,因为它多次访问文件系统。提出的大多数解决方案使用更多 RAM,但执行速度也更快。祝你好运。
【解决方案2】:

您可以通过减少访问文件系统的频率来加快速度。您一次从文件中读取一个整数,因此每次都通过循环访问文件。

请尝试一次读取整个文件或文件的一大块。 (这称为块读取)。您可以将其缓冲到数组中。在循环内部,从内存缓冲区而不是文件中读取。如果您没有读入整个文件,请在循环内根据需要刷新内存缓冲区。

【讨论】:

    【解决方案3】:

    使用fgets() 一次将一行读入行缓冲区。将行缓冲区解析为整数值。

    这个函数减少了你从文件中读取的次数,因为在幕后,fgets() 从文件中读取大量数据并且一次返回一行。只有在其内部缓冲区中没有更多行时,它才会尝试读取另一个块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 2018-10-04
      • 2016-02-01
      相关资源
      最近更新 更多