【问题标题】:how to perform reversing a sentence Word by Word in C?如何在C中逐字执行反转句子?
【发布时间】:2012-03-26 16:54:00
【问题描述】:
#include <stdio.h>

int main(void)
{
  int i,j;
  int wordstart = -1;
  int wordend = -1;
  char words[]= "this is a test";
  char temp;

  // Reverse each word
  for (i = 0; i < strlen(words); ++i)
  {
    wordstart = -1;
    wordend = -1;
    if(words[i] != ' ') 
      wordstart = i;
    for (j = wordstart; j < strlen(words); ++j)
    {
      if(words[j] == ' ')
      {
        wordend = j - 1;
        break;
      }
    }
    if(wordend == -1)
      wordend = strlen(words);
    for (j = wordstart ; j <= (wordend - wordstart) / 2; ++j)
    {
      temp = words[j];
      words[j] = words[wordend - (j - wordstart)];
      words[wordend - (j - wordstart)] = temp;
    }
    i = wordend;
    printf("reversed string is %s:", words);
  }
}

我尝试过这种方式,但我得到了这个输出:
siht is a test
我的预期输出是:
test a is this

如果有人可以提出一种不同的方法,这种方法的时间复杂度非常低,或者如果它是正确的方法,我将不胜感激。谢谢

【问题讨论】:

  • @MichaelBurr 你能指出我犯的错误吗

标签: c string performance algorithm cstring


【解决方案1】:

您可以创建一个双链表作为基础数据结构。然后,遍历单词并在找到它们时将它们插入列表中。

当您到达句子的末尾时,只需向后遍历列表并在遍历时打印单词

【讨论】:

  • 我是 c 的初学者,我不知道链表的应用,所以你能指出我程序中的错误或建议我使用链表以外的其他方法
  • @GEEKmax 你调试过你的代码,看看有什么问题。请不要开始您的 StackOverflow 体验,以为我们是来为您做作业的。我们可以帮助您解决具体问题。
  • @Lucian Grigore 抱歉,这不是我的意图,我是 C 语言的初学者,至少需要一个小时来调试它
【解决方案2】:

从最后一个字符开始标记该行并继续到第一个字符。保持一个指针锚定在当前单词的底部,另一个指针在找不到单词开头时会减小。当您在像这样扫描时发现单词开始时,从单词开始指针打印到单词结束锚点。将单词结束锚点更新为当前单词开始字符的前一个字符。

您可能希望在扫描时跳过空格字符。

更新

这是一个快速的实现:

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define MAX_BUF 256

void show_string (char *str, int i, int n)
{
  while (i <= n)
  {
    printf ("%c", str[i]);
    i++;
  }
}

int main (void)
{
  char str[MAX_BUF];
  int end_anchor, start_ptr;
  int state;

  printf ("\nEnter a string: ");
  scanf (" %[^\n]", str);

  start_ptr = strlen (str) - 1;

  end_anchor = start_ptr;
  state = 0;
  while (start_ptr >= -1)
  {
    switch (state)
    {
      case 0:
             if ((!isspace (str[start_ptr]) && (start_ptr >= 0)))
             {
               start_ptr--;
             }
             else
             {
               state = 1;
             }
             break;

      case 1:
             show_string (str, start_ptr + 1, end_anchor);
             state = 2;
             start_ptr--;
             printf (" ");
             break;

      case 2:
             if (!isspace (str[start_ptr]))
             {
               state = 0;
               end_anchor = start_ptr;
             }
             else
             {
               start_ptr--;
             }
             break;
    }
  }


  printf ("\n");
  return 0;
}

end_anchor 指向每个结束词,start_ptr 查找结尾由end_anchor 保存的词的开头。当我们找到一个单词开始时(通过空格字符或start_ptr = -1),我们打印从start_ptr + 1end_anchor 的所有字符。 + 1 是因为实现:start_ptr 指向空格字符,打印例程将打印从in 的所有字符。一旦我们检测到一个空格,我们就打印它并跳过相邻的空格(在case 2 中)并只保留一个手动打印的空格。一旦检测到非空格,我们就会得到另一个单词结尾,为此我们将case 2中的这个索引设置为end_anchor,并设置state = 0,这样我们就可以再次搜索单词start。

【讨论】:

  • 你的意思是拿两个指针,一个最初指向开始,另一个指向最后,我不明白你能说清楚吗
  • 这一行是做什么的 scanf (" %[^\n]", str);
  • 跳过字符串开头的空格并读取直到找不到\n,即。读取包含空格的字符串。
  • 是的,有什么可以从语法上理解的,因为它很难记住
  • 你可以使用任何东西,比如fgets 来获取字符串,或者其他什么,这不是主要问题。
【解决方案3】:

我将使用类似于strrchr 的写入函数来查找' ' 的最后出现,如果找到后面的打印字,则用'\0' 重写此' ' 并循环重复,直到找不到更多字.最后我会再次打印这个字符串的内容,因为在第一个单词之前很可能没有' '

我会编写自己的函数而不是strrchr,因为strrchr 计算给定字符串的长度,在这种情况下这是多余的。该长度不必计算多次。

代码如下:

char* findLastWord(char* str, int* len)
{
    int i;
    for (i = *len - 1; i >= 0; --i)
    {
        if (str[i] == ' ')
        {
            str[i] = '\0';
            if (i < *len - 1)
            {
                *len = i - 1;
                return &str[i + 1];
            }
        }
    }
    return NULL;
}

int main (int argc, char *argv[])
{
    char str[] = " one two three  four five six ";
    int len = strlen(str);

    char* lastWord = findLastWord(str, &len);
    while (lastWord != NULL)
    {
        printf("%s\n", lastWord);
        lastWord = findLastWord(str, &len);
    }
    if (len > 1)
        printf("%s\n", str);
    return 0;
}

输出:

six
five
four
three
two
one

希望这会有所帮助;)

【讨论】:

    【解决方案4】:

    也许这属于代码审查网站?

    您的方法对我来说似乎非常有效(除了我只会调用一次 strlen(words) 并将结果保存在寄存器中)。

    两个可能的错误如下所示:

    wordend = strlen(words);
    

    应该是

    wordend = strlen(words)-1;
    

    for(j = wordstart ; j <= (wordend - wordstart) / 2 ; ++j) {
    

    应该是

    for(j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) {
    

    最终代码看起来像(带有一些额外的 {}):

        #include <stdio.h>
        int main(int argc,char *argv[])
        {
            int i,j;
            char words[]= "this is a test";
            int L=strlen(words);
    
            // Reverse each word
            for(i = 0; i < L; ++i) {
              int wordstart = -1;
              int wordend = -1;
              if(words[i] != ' ') 
              {
                wordstart = i;
    
                for(j = wordstart; j < L; ++j) {
                  if(words[j] == ' ') {
                    wordend = j - 1;
                    break;
                  }
                }
                if(wordend == -1)
                  wordend = L-1;
                for(j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) {
                  char temp = words[j];
                  words[j] = words[wordend - (j - wordstart)];
                  words[wordend - (j - wordstart)] = temp;
                }
                i = wordend;
              }
            }
            printf("reversed string is %s:",words);
            return 0;   
        }
    

    【讨论】:

    • 你能告诉我程序的命令模式执行为什么这个 main(int argc,char *argv[]) 有用
    • 哦,对不起,这只是我的习惯。它对你的程序一点帮助都没有。
    【解决方案5】:
    if(words[i] != ' ') 
        wordstart = i;
    

    这个语句的else部分呢?如果 words[i] == ' ',并且 wordstart 保持 -1。 所以也许尝试使用:

    while (words[i] && words[i] == ' ') ++i;
      if (!words[i])
          break;
    wordstart = i;
    

    然后你应该从 i 循环中输出结果。 最后,如果你想得到你期望的结果,你应该把整个句子再反转一次,用你在循环中使用的方式。

    【讨论】:

    • dint get 你能告诉我我在哪里用你的代码替换我的代码
    【解决方案6】:
    #include<stdio.h>
    #include<string.h>
    
    void reverse(char *str, size_t len)
    {
        char tmp;
        size_t beg, end;
        if (len <=1) return;
    
        for (beg=0,end=len; beg < --end ; beg++) {
            tmp = str[beg];
            str[beg] = str[end];
            str[end] = tmp;
        }
    }
    
    int main(void)
    {
        char sentence[] = "one two three four five";
        size_t pos, len;
    
        printf("Before:%s\n",sentence);
        for (pos = len= 0;  sentence[pos]; pos += len) {
            pos += strspn( sentence+pos, " \t\n" );
            len = strcspn( sentence+pos, " \t\n" );
            reverse ( sentence + pos, len );
            }
        reverse ( sentence , pos );
    
        printf("After:%s\n",sentence);
    
        return 0;
    }
    

    【讨论】:

      【解决方案7】:
       #include <iostream>
       #include <string>   
        using namespace std;
        char* stringrev(char s[], int len)
        {
          char *s1 = (char*)malloc(len+1);
          int i=0;
          while (len>0)
          {
            s1[i++] = s[--len];
          }
         s1[i++] = '\0';
          return s1;   
        }
      
         void sentrev(char s[], int len)
       {
          int i=0; int j=0;
           char *r = (char*)malloc(len+1);
           while(1)
           {
           if(s[j] == ' ' || s[j] == '\0')
           {
             r = stringrev(s+i, j-i);
             i = j+1;
             cout<<r<<" ";
           }
          if (s[j] == '\0')
          break;
          j++;
         }
      
       }
      
      
      int main()
      {
      char *s = "this is a test";
      char *r = NULL;
      int len = strlen(s);
      cout<<len<<endl;
      r = stringrev(s, len);
      cout<<r<<endl;
      sentrev(r, len);
      return 0;
      }
      

      上面的代码snap反转句子,使用char *r 和打印cout

      【讨论】:

      • 上面的代码在 sentrev() 函数中使用 char *r 并在里面打印 cout
      【解决方案8】:
      #include<stdio.h>
      #include<conio.h>
      #include<string.h>
      int main()
      {
      char st[50], rst[50];
      printf("Enter the sentence...\n");
      gets(st);
      int len=strlen(st), p;
      int j=-1,k;
      p=len;
      for(int i=(len-1); i>=0; i--)
      {
          //searching for space or beginning
          if(st[i]==' ')
          {
              //reversing and storing each word except the first word
              for(k=i+1;k<p;k++)
              {
                  //printf("%c",st[k]);
                  rst[++j]=st[k];
              }
              j++;
              rst[j]=' ';
              printf("\n");
              p=i;
          }
          else if(i==0)
          {
              //for first word
              for(k=i;k<p;k++)
              {
                  //printf("%c",st[k]);
                  rst[++j]=st[k];
              }
          }
      
      }
      printf("Now reversing the sentence...\n");
      puts(rst);
      return 0;
      }
      

      【讨论】:

        【解决方案9】:

        使用main for循环遍历到句尾: 复制字符串中的字母,直到找到空格。 现在调用add@beginning 函数,并在每次将字符串传递给链表时在该函数中添加字符串。 打印链接列表的内容,中间有一个空格以获得预期的输出

        【讨论】:

        • 您的答案可能受益一些源代码示例。
        【解决方案10】:

        我的代码,只是从最后一个开始遍历,如果你发现一个空格打印它之前的字符,现在将结尾更改为空格-1;这将打印到第二个单词,最后只使用一个 for 打印第一个单词loop.Comment 更改方法。

        程序:

        #include<stdio.h>
        int main()
        {
         char str[200];
        int i,j,k;
        scanf("%[^\n]s",&str);
        for(i=0;str[i]!='\0';i++);
        i=i-1;
        for(j=i;j>=0;j--)
        {
            if((str[j])==' ')
            {
                for(k=j+1;k<=i;k++)
                {
                    printf("%c",str[k]);
                }
                i=j-1;
                printf(" ");
            }
        
        }
        for(k=0;k<=i;k++)
        {
            printf("%c",str[k]);
        }
        }
        

        【讨论】:

          【解决方案11】:

          我们只需使用为满足我们需求而定制的 n*1 2D 字符数组!!!

          #include <stdlib.h>
          
          int main()
          {
              char s[20][20];
              int i=0, length=-1;
              for(i=0;;i++)
              {
                  scanf("%s",s[i]);
                  length++;
                  if(getchar()=='\n')
                      break;
              }
              for(i=length;i>=0;i--)
                  printf("%s ",s[i]);
              return 0;
          }
          

          【讨论】:

          • 这是最简单的方法......它很棒。
          【解决方案12】:
          using stack 
          
          #include <iostream>  
          #include <stdio.h>
          #include <stack>
          
          int main()
          { 
          
              std::stack<string> st;
              char *words= "this is a test";
              char * temp =   (char *)calloc(1, sizeof(*temp));
              int size1= strlen(words);
              int k2=0;
              int k3=0;
              for(int i=0;i<=size1;i++)
              {
                 temp[k2] = words[i];
                 k2++;
                  if(words[i] == ' ')     
                  {  
                      k3++;
                      if(k3==1)
                          temp[k2-1]='\0';
          
                      temp[k2]='\0';
                      st.push(temp);
                      k2=0;           
                  }
                  if(words[i] == '\0')
                  {
                      temp[k2]='\0';
                      st.push(temp);
                      k2=0;
                      break;
                  }               
              }
          
            while (!st.empty())
            {
                 printf("%s",st.top().c_str());
                  st.pop();
            }
          

          【讨论】:

            猜你喜欢
            • 2020-07-13
            • 2011-05-14
            • 1970-01-01
            • 2013-11-03
            • 1970-01-01
            • 2016-08-06
            • 2013-01-29
            • 2020-12-29
            • 1970-01-01
            相关资源
            最近更新 更多