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

C 比较文件中相邻行的更好算法,c,C,我已经完成了作业(是的,这是一门编程课),但恐怕我没有以最有效的方式完成。它基本上是uniq程序,它将比较文件中的相邻行,并且只打印任何重复行的一个副本。注意:printUniq()是我自己的函数,它考虑了各种标志,readline()是另一个函数,它使用malloc和realloc将任意长度的行读入char*缓冲区。以下是我担心的部分: if(prevline != NULL) { while(thisline != NULL) { while(thisline != NUL

我已经完成了作业(是的,这是一门编程课),但恐怕我没有以最有效的方式完成。它基本上是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);
        }
     }  
  }
有没有更好的方法来组织这个项目?我讨厌在一个循环中三次检查这行是否为空。外部while循环中的第一个空检查是必需的,如果最后一行重复,则需要嵌套while中的下一个检查。调用free之后的下一个检查基本上是检查“复制循环”是否因为该行为null而退出,如果不是,它将允许程序获得另一行。然后,下一个检查只针对文件中的最后一行,因为如果它不在那里,当readline返回null(文件中没有更多行)时,循环退出,并且prevline从未打印

无论如何,任何帮助都是感激的

使用
(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

处理循环外的一行使第一种方法更简单。流程对我来说似乎很清楚。有一条线吗?有第二条线路吗?好吧,独特性是有意义的

在第二种方法中,处理循环中的一行意味着维护开发人员将为每一行输入查看第一行测试,IMHO更让他们担心

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

此外,一行文件逻辑位于循环之后(不太清晰,IMHO),需要mre逻辑。如果程序打算模拟其他
uniq
功能,如打印每行计数,则需要此逻辑

第二种方法的明显好处是在一个位置读取文件,这通常是一种很好的策略。嗯,如果readline写得好,那没什么大不了的

总结:第一种方法需要更少的逻辑,事件的顺序更明确,因此更容易理解。第二个在一个位置读取文件,但需要在循环外部处理最后一个重复组,因此它甚至更长。通常,如果正在编程uniq,则逻辑性也更高

注意:这两个流都可以工作

使用
(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

处理循环外的一行使第一种方法更简单。流程对我来说似乎很清楚。有一条线吗?有第二条线路吗?好吧,独特性是有意义的

在第二种方法中,处理循环中的一行意味着维护开发人员将为每一行输入查看第一行测试,IMHO更让他们担心

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

此外,一行文件逻辑位于循环之后(不太清晰,IMHO),需要mre逻辑。如果程序打算模拟其他
uniq
功能,如打印每行计数,则需要此逻辑

第二种方法的明显好处是在一个位置读取文件,这通常是一种很好的策略。嗯,如果readline写得好,那没什么大不了的

总结:第一种方法需要更少的逻辑,事件的顺序更明确,因此更容易理解。第二个在一个位置读取文件,但需要在循环外部处理最后一个重复组,因此它甚至更长。通常,如果正在编程uniq,则逻辑性也更高


注意:这两个流都可以工作

我建议只在一个地方读取文件,因为这样会使代码更易于管理。也许像这样的事情可以奏效:

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);

我建议只在一个地方读取该文件,因为这样会使代码更易于管理。也许像这样的事情可以奏效:

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);

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);

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);

这非常有帮助,我实际上使用了您为while循环建议的检查,然后在循环中使用了一个简单的if-else来处理重复项。@shumanish-IMHO,一个算法明显优于另一个算法,因为它的逻辑更少,事件流更简单、更明确。第二种方法的主要问题是,除非添加循环后的代码,否则它在单行文件的
uniq
的一般情况下不起作用。例如,UNIX
uniq
将打印所有带有计数的行