提高效率 - 字计数器

时间:2017-03-30 18:06:34

标签: c

我正在阅读一些C编程问题,我想确保我的基础知识有所下降。目前我正在讨论一个词:

问:写一个函数,它将确定给定字符串中有多少个单词。你可以假设一个或多个 连续的空格是单词之间的分隔符,并且传递给函数的字符串为空终止。

我得到了工作,但效率很重要。我想知道它是如何改进的。除#include(stdio.h)之外,必须使用指针而没有其他库谢谢!

#include <stdio.h>
int word_counter(char string[])
{
  //We start with first word unless we have a empty string then we have no words
  int count;
  if(*string!='\0'){
    count=1;
}
  else{
    count=0;
    return 0;
  }
  //while we dont reach the end of the string
  while(*string!='\0'){
    //if we detect a whitespace
    if(*string==' '){
      //get previous character
      string--;
      // If previous character is not a space we increase the count
      // Otherwise we dont since we already counted a word
      if(*string!=' '){
        count++;
      }
      //return pointer to current character
      string++;
    }
    // set pointer to next character
    string++;
  }
  return count;
}

//just to test if it works
int main(void) 
{
    char str[] = "Hello World!";
    printf("How many words? = %i\n", word_counter(str));
    return 0;
}

1 个答案:

答案 0 :(得分:0)

查看代码,我发现空字符串的初始条件有一个特殊情况。有时,尽早获得初始条件会简化算法的其余部分,有时您可以通过更改查看问题的方式来消除它。这次是第二次。

如果您将此视为计算单词之间的边界,则算法会变得更简单。有两种方法可以从正面和背面定义单词边界。

"  Prestidigitation  \n"
   ^               ^
   front           back

我们是否在空白字符后面寻找非空白字符?或者我们是否在非空白字符后寻找空白字符?

你也有在字符串(string--)中向后看的代码,这通常是不安全的,因为如果字符串以空格开头怎么办?然后你已经从弦上向后走了,所以应该避免向后移动。

最后,问题是字符串末尾是否有空格。我们必须特殊情况下字符串的结尾。

所以看第一个单词边界是要走的路:一个空白字符后面的非空白字符。我们将跟踪前一个角色的状态(last_was_space以下),而不是向后看。

这是一个空格字符后面的非空格字符。如果字符串不以空格开头怎么办?

"Basset hounds got long ears."
 ^
 What about this?

由于我们有last_was_space,我们可以将它初始化为true并假装字符串的开头以空格开头。这也处理领先的空格,如" this is four words"

最后,有更多类型的空间,而不仅仅是空格,如tab和换行以及其他奇特的东西。我们可以使用if( *space == ' ' || *space == '\n' == ... )来使事情整洁有效,而不是写switch。这是一种罕见的案例,你想利用它的“堕落”机制为多个案件做同样的事情。

#include <stdio.h>

// Note that it's `const` since we don't touch the string memory.
int word_counter(const char string[]) {
    // Start with no words.
    int count = 0;

    // Pretend every word starts with space.
    short last_was_space = 1;

    // Using a for loop to make the movement of the pointer more apparent
    for( ; *string!='\0'; string++ ) {
        // A switch can be faster than an if/else if.
        switch( *string ) {
            // There's more than one type of whitespace.
            // These are from isspace().
            // It takes advantage of switch's fall through.
            case ' ':
            case '\t':
            case '\n':
            case '\r':
            case '\v':
            case '\f':
                // Remember we saw a space.
                last_was_space = 1;
                break;
            default:
                if( last_was_space ) {
                    // Non-whitespace after space, count it
                    count++;

                    // Remember we didn't see a space.
                    last_was_space = 0;
                }
                break;
        }
    }

    return count;
}

通常情况下,我会使用stdbool.h中的boolctype.h中的isspace,但您的练习只能使用stdio.h