用于比较文件中相邻行的更好算法

时间:2012-04-07 21:08:41

标签: c

我已经完成了作业(是的,它适用于编程课程),但我恐怕没有以最有效的方式进行。它基本上是uniq程序,它将比较文件中的相邻行,并且只打印任何重复行的一个副本。一些注意事项:printUniq()是我自己的函数,它考虑了各种标志,readline()是另一个使用malloc和realloc将任意长度的行读入char *缓冲区的函数。以下是我担心的部分:

if(prevline != NULL)
{
  while(thisline != NULL)
  {
     while(thisline != NULL && strcmp(prevline, thisline) == 0)
     {
        count++;
        free(prevline);
        prevline = thisline;
        thisline = readline(stream);
     }
     printUniq(prevline, cflag, dflag, uflag, count);
     count = 1;
     free(prevline);
     if (thisline != NULL)
     {
        prevline = thisline;
        if((thisline = readline(stream)) == NULL)
        {
           printUniq(prevline, cflag, dflag, uflag, count);
        }
     }  
  }

有没有更好的方法来构建这个程序?我讨厌在循环中将此行检查为NULL三次。外部while循环中的第一次NULL检查是必要的,如果最后一行是重复的,则需要嵌套while中的下一次检查。调用free之后的下一次检查基本上检查是否由于thisline为null而退出“Duplicate loop”,如果没有,它将允许程序获得另一行。然后下一个检查仅用于文件中的最后一行,因为如果它不存在,当readline返回null(文件中没有更多行)时,循环退出并且从不打印prevline。

无论如何,任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:2)

我建议只在一个地方阅读该文件,因为它会使代码更易于管理。也许这样的事情可能有用:

prevline = NULL;
count = 1;
while ((thisline = readline(stream)) != NULL) // will stay in the loop for as long as it reads from file
{
    if (prevline == NULL)
    { // this is the first read from file
         prevline = thisline;
         continue;

    }

    if (strcmp(thisline, prevline) == 0)
    {
         count++;
    } else // found a different line
         if (count > 1) // but after I already counted several identical
         {    // so I will print the line
                printUniq(prevline, cflag, dflag, uflag, count);
                count = 1;
         }
    free(prevline);
    prevline = thisline;
}
if (count > 1) and (prevline != NULL)
{
     printUniq(prevline, cflag, dflag, uflag, count);
}
free(prevline);

答案 1 :(得分:1)

使用(thisLine = readline()) != NULL作为循环的条件,并且一次只读取一个行,意味着循环停止在文件的末尾,并且只有在此线路有效时才能输入循环。

它可以在循环外读取prevLine,或者在循环中不处理前一行:

if ((thisLine = readline()) != NULL) {
    char* prevLine = thisLine;                // got one line
    while ((thisLine = readline()) != NULL) {
       if (strcmp(...) == 0) {
           ...
       } else {
           ...
       }
       ...
    }
    ... deal with prev_line, no need for if because it *must* have been read.
}

VS

prevLine = NULL;
while ((thisLine = readline()) != NULL) {
    if (prevLine == NULL) { // first line?
       ...
    } else if (strcmp(...) == 0) {
       ...
    } else {
       ...
    }
       ...
    prev_line = this_line
}
if (prev_line != NULL) {
   ...
} else {          // only one line in the file?
   ...
}

处理循环外的一行使第一种方法更简单。这个流程对我来说非常清楚。有一条线吗?有第二行吗?好吧,唯一性有意义......

在第二种方法中,处理循环内的一行意味着维护开发人员将查看每行输入的第一线测试,恕我直言,他们更担心。

循环后的代码是必要的,因为文件的最后两行或更多行可能会重复,这种情况也需要调用printUnique。

此外,单行文件逻辑在循环之后(不太清楚,恕我直言)并且需要mre逻辑。如果程序旨在模拟其他uniq功能,例如使用计数打印每个行,则需要此逻辑。

第二种方法的明显好处是在一个地方读取文件,这通常是一个很好的策略。恕我直言,如果正确写入readline,它并不重要。

总结:第一种方法需要较少的逻辑,事件的顺序更明确,因此理解起来更简单。第二个在一个地方读取文件,但需要在循环外处理最后一个重复组,因此它甚至更长。如果uniq一般被编程,那么它也更具逻辑性。

注意:这两个流程都有效。

答案 2 :(得分:0)

Mihai的建议可以通过使用for()循环而不是while循环来进一步简化,并且通过使用continue语句(大多数)可以避免嵌套条件和重复逻辑:

dupstate = 0; uniqcount = 0; totdup = 0; linenum = 0;
for (prevline=NULL; thisline=readline(stream); free(prevline),prevline=thisline) {
{
    linenum++;
    if (!prevline || strcmp(thisline, prevline))
    {
         uniqcount++; dupstate = 0;
         printUniq(thisline, cflag, dflag, uflag, uniqcount);
         continue;
    }
    totdup++;

    if (!dupstate++) /* only the first dup is reported */
    {    
         printDup(thisline, cflag, dflag, uflag, totdup); 
    }
 }

 free(prevline);
相关问题