【问题标题】:Reversing the word order in a string in place反转字符串中的单词顺序
【发布时间】:2011-11-07 09:59:26
【问题描述】:

我正在尝试将句子中的单词顺序颠倒过来,例如:

这句话是倒过来的。

变成

反转。是单词句子这个

这是我到目前为止所拥有的,几乎可以正常工作: 我使用 strrev 函数反转字符串,然后使用 inprev 函数将每个单词单独发送到 strrev 函数,将它们反转回原始方向,但顺序相反。 为 strrev 函数的开头和结尾发送一个指针可能看起来有点傻,但它允许在 inprev() 中使用相同的函数,发送一个指向单个单词开头和结尾的指针。

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

void strrev(char * start, char * end);
void inprev(char * start);

int main(void)
{
   char str[] = "Foobar my friends, foobar";
   char * end = (str + strlen(str) -1);
   puts(str);
   strrev(str, end);
   puts(str);
   inprev(str);

   puts(str);

   return 0;
}

void strrev(char * start, char * end)
{
   char temp;

while (end > start)
   {
     temp = *start;
     *start = *end;
     *end = temp;
      start++;
      end--;
   }
}

void inprev(char * start)
{
     char * first = start;
     char * spcpnt = start;
     while (*spcpnt)
     {
        while (*spcpnt != ' ' && *spcpnt)
           spcpnt++;
        strrev(start, spcpnt-1);         // removing the -1 sends the space on the 
        start = spcpnt++;                // other side to be reversed, doesn't stop 
                                         // the problem.  

     }

}

这是输出:

Foobar 我的朋友们,foobar

raboof ,sdneirf ym rabooF

foobarfriends,我的 Foobar

问题是最后一个单词的末尾缺少最后一个空格意味着该单词和最后一个字符串中的前一个单词之间缺少一个空格,而是被扔到最后一个单词的末尾,这是原始字符串中的第一个单词。发送单词另一侧的空格只会将问题转移到其他地方。任何人都可以看到解决方案吗?

【问题讨论】:

  • 遇到X空格怎么办?它们属于之前还是之后的词?
  • +1 好问题 :)。如果我有一点时间,我会提供一个解决方案
  • 我猜你不想让第一个字母变大,正如你的例子所示......
  • @RedX 没想到,我再看看我的算法,想办法
  • @imacake 正确,错字。谢谢。

标签: c string algorithm


【解决方案1】:

您只需在inprev 函数中移动start 指针即可跳过单词之间的空格。由于这似乎是家庭作业(如果我错了,请纠正我)我只想说你需要做的就是移动一位操作员的位置。

但是,这会产生一个问题,即inprev 执行缓冲区溢出,因为搜索没有正确终止。更好的方法是:

while not end of string
  search for start of word
  start = start of word
  search for end of word
  strrev (start, end)

这也将处理多个空间。此外,U+0020(ASCII 32,一个空格)不是唯一的空白字符。有测试字符的标准库函数。它们在 中并以 is... 开头,例如isspace.

【讨论】:

  • 谢谢!用我的固定算法更新了原始问题。顺便说一句,不是家庭作业,在求职面试问题准备中看到它,并认为我会从中获得乐趣。
  • @Matt 请不要修复问题中的原始代码!这使得这个问题对于将来阅读它的任何人都毫无用处。我会回滚那个编辑。
  • @Matt:要添加到 razlebe 的评论中,您可以发布更新的代码作为答案,而不是编辑问题。
  • @Matt - 没有伤害。 :) 轻松回滚。不过,我同意 Skizz - 如果您可以发布您的固定代码作为答案,以帮助未来的读者完全理解该修复,那就太好了。
  • @razlebe:会的,不过显然我得等 5 个小时。
【解决方案2】:

想出了一个解决办法;这是我修改后可以正常工作的函数。

void inprev(char * str)
{
    _Bool inword = 0;
    char * wordend;
    char * wordstart;

     while(*str)
     {
         if(!isspace(*str) && (inword == 0))
         {
             wordstart = str;
             inword = 1;
         }
         else if (isspace(*str) && (inword == 1))
         {
             wordend = str-1;
             inword = 0;
             strrev(wordstart, wordend);
         }

         str++;
     }

     if (*str == '\0')
        strrev(wordstart, str-1);

}

char * wordend 是不必要的,因为您可以将 str-1 传递给 strrev 函数,但它可以更清楚地说明发生了什么。

【讨论】:

    【解决方案3】:

    如果您不使用指针而是使用偏移量,有时事情会变得更容易。 strspn() 和 strcspn() 库函数或多或少地强制您使用偏移量, 并很好地处理字符串结尾的情况。

    #include <stdio.h>
    #include <string.h>
    
    size_t revword(char *str);
    void revmem(void *ptr, size_t len);
    
    size_t revword(char *str) {
    size_t pos,len;
    
    for (pos=len=0; str[pos]; pos += len) {
            len = strspn( str+pos, " \t\n\r");
            if (len) continue;
            len = strcspn( str+pos, " \t\n\r");
            if (!len) continue;
            revmem( str+pos, len );
            }
    revmem( str, pos );
    return len;
    }
    
    void revmem(void *ptr, size_t len)
    {
    size_t idx;
    char *str = (char*) ptr;
    
    if (len-- < 2) return;
    
    for (idx = 0; idx < len; idx++,len--) {
            char tmp = str[idx];
            str[idx] = str[len];
            str[len] = tmp;
            }
    }
    
    int main (int argc, char **argv)
    {
    
    if (!argv[1]) return 0;
    revword(argv[1] );
    printf("'%s'\n", argv[1] );
    
    return 0;
    }                                                                                           
    

    【讨论】:

    • 你能添加一些 cmets 来解释发生了什么吗?有点难以理解,例如,revword 函数中发生了什么。
    • 好吧:在循环中,我测量连续空格的长度(strspn() 调用),然后跳过它。之后,我测量连续 NON 空格(strcspn() 调用)的长度并将其反转。在循环结束时,我累积了字符串的整个长度并反转整个字符串。
    【解决方案4】:

    以下算法是就地的,分两步运行。首先它反转整个字符串。然后它反转每个单词。

    #include <stdio.h>
    
    void reverse(char *str, int len)
    {
        char *p = str;
        char *e = str + len - 1;
    
        while (p != e) {
            *p ^= *e ^= *p ^= *e;
            p++;
            e--;
        }
    }
    
    void reverse_words(char *str)
    {
        char *p;
    
        // First, reverse the entire string
        reverse(str, strlen(str));
    
        // Then, reverse each word
        p = str;
        while (*p) {
            char *e = p;
            while (*e != ' ' && *e != '\0') {
                e++;
            }
    
            reverse(p, e - p);
            printf("%.*s%c", e - p, p, *e);
    
            if (*e == '\0')
                break;
            else
                p = e + 1;
        }
    }
    
    int main(void) {
        char buf[] = "Bob likes Alice";
        reverse_words(buf);
        return 0;
    }
    

    【讨论】:

    • 如果len 是偶数,函数reverse 将导致段错误。试试while (p &lt; e)
    【解决方案5】:
    void reverse_str(char* const p, int i, int j) // helper to reverse string p from index i to j
    {
        char t;
        for(; i < j ; i++, j--)
            t=p[i], p[i]=p[j], p[j]=t;
    }
    
    void reverse_word_order(char* const p) // reverse order of words in string p
    {
        int i, j, len = strlen(p);  // use i, j for start, end indices of each word
    
        reverse_str(p, 0, len-1);      // first reverse the whole string p
        for(i = j = 0; i < len; i = j) // now reverse chars in each word of string p
        {
            for(; p[i] && isspace(p[i]);) // advance i to word begin
                i++;
            for(j = i; p[j] && !isspace(p[j]);) // advance j to past word end
                j++;
            reverse_str(p, i, j-1);  // reverse chars in word between i, j-1
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-03
      • 1970-01-01
      • 2021-12-09
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      相关资源
      最近更新 更多