如何使用递归计算字符串中的元音

时间:2014-05-13 16:12:57

标签: c++ recursion

我正在尝试使用递归来计算字符串中的元音数量。以下是我到目前为止的情况:

int vowels(string str, int pos, int length)
{
    if (str.length() == 0)
    return 0;

    switch (str[pos])
    {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
      case 'A':
      case 'E':
      case 'I':
      case 'O':
      case 'U':
        return 1 + vowels(str.substr(1), pos, length);
      default:
        return vowels(str.substr(1), pos, length);
    }
}

int main()
{
    string str;
    int len;

    cout << "Enter a string: ";
    getline(cin, str);
    cout << endl;

    len = static_cast<int>(str.length());

    cout << "Number of vowels in \"" << str << "\" = "
         << vowels(str, 0, len) << endl;

    return 0;
}

问题是,我需要在第一次调用元音函数时将pos设置为0,而不是在后续的递归调用中将其重置为0。另外,我不需要使用子串,而是需要在每次递归调用元音()之前递增pos。此外,基本情况应该是pos == length(当没有更多字符要检查字符串时)。

4 个答案:

答案 0 :(得分:1)

好像你忘了增加pos:

/* inside the vowels function switch statement */
return 1 + vowels(str.substr(1), pos+1, length);
    default:
return vowels(str.substr(1), pos+1, length);

此外,如果将递归条件的结尾更改为“pos == str.length()”,则根本不需要str.substr(...)。另外,如果跳过substr(...),则通过const引用传递std :: string(这是一个好习惯)。

答案 1 :(得分:1)

实现这一目标的方式与西伯利亚夏季的白天时间一样多。从简单开始。将条件逻辑与枚举分开。无论条件(它是元音)是否真实,你总是转到下一个要测试的字符(或者你完成了你的字符串和你刚刚完成的字符)。所以从一个脑死亡的简单条件检查开始:

static bool is_vowel(char c)
{
    return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
            c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
}

一旦你有了这个,设计一个简单的方法来走你的字符串。 C ++ 重度提升了迭代器模型,这也不例外:

// string iterator examiner
static int count_vowels(std::string::const_iterator cur, std::string::const_iterator end)
{
    return (cur == end) ? 0 : is_vowel(*cur) + count_vowels(std::next(cur), end);
}

最后,设计一种从调用方调用它的方法,而不必直接指定那些迭代器:

// friendly wrapper for checking a string for vowels.
int count_vowels(const std::string& s)
{
    return count_vowels(s.begin(), s.end());
}

结果是一个可调用的接口,使用如下:

int main()
{
    std::string s = "A simple string for testing vowel counting.";
    std::cout << count_vowels(s) << '\n';
    return 0;
}

<强>输出

12

非递归替代:更好的方式

老实说,这是执行您所负责的操作的可怕方式,尽管它至少会向您介绍递归。如果您对如何执行此操作感兴趣没有递归,我们可以使用我们编写的简单条件函数(is_vowel()),使用标准库提供的更好的算法count_if。这样,您的递归可以被删除并替换为:

// friendly wrapper for checking a string for vowels.
long vowels(const std::string& s)
{
    return std::count_if(s.begin(), s.end(), is_vowel);
}

结果将是相同的,并且直观地说,函数名称清楚地表明您正在做什么:计算字符串中is_vowel为真的所有字符。

祝你好运,我希望你能从中得到一些东西。

答案 2 :(得分:0)

我会按以下方式定义函数

#include <cstring>
#include <string>

std::string::size_type count_vowels( const std::string &s, 
                                     std::string::size_type pos, 
                                     std::string::size_type length )
{
   const char *vowels = "aeiouAEIOU";

   if ( s.length() <= pos || length == 0 ) return 0;

   return ( s[pos] && std::strchr( vowels, s[pos] ) != 0 ) + 
          count_vowels( s, pos + 1, length - 1 );
}

并使用您的方法

#include <string>

std::string::size_type count_vowels( const std::string &s, 
                                     std::string::size_type pos, 
                                     std::string::size_type length )
{
    if ( s.length() <= pos || length == 0 ) return 0;

    std::string::size_type n = 0;

    switch ( s[pos] )
    {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
        case 'A':
        case 'E':
        case 'I':
        case 'O':
        case 'U':
            ++n;
        default:
            return n + count_vowels( s, pos + 1, length - 1 );
    }
}

答案 3 :(得分:0)

您不应该使用递归来解决此问题。有时在进行C ++开发时使用递归是明智的,但对于一般用途,缺少tail-call elision代表了一点性能瓶颈。一般来说,如果递归过程每次调用只调用一次,那么最好使用循环。如果一个recusive进程调用自己两次(例如,下降到树型数据结构的左右分支,或者可能计算一个fibonacci序列),它可能更容易使用递归函数一个循环。

尽管如此,这显然是一项家庭作业,而合理的软件开发实践也没有。

传入poslength以及string似乎很愚蠢...... C ++已经为您提供了一个很好的通用工具来处理迭代集合(和一个字符串只是一个可迭代的字符集合,以... Iterators的形式出现!

迭代器有效地将“位置”的概念封装在容器中。 string::begin()会为您指定一个指向字符串开头的迭代器,string::end()会指向一个指向结尾的Iterator。您可以取消引用非结束迭代器以获取它指向的字符(很像指针),并递增迭代器以将其前进到集合中的下一个元素。

这是一个简单计算字符数量的例子,但我相信你能够根据自己的需要进行调整。

template<class Iterator>
int count_characters(Iterator begin, Iterator end)
{
    // if we're at the end of the string, there's nothing more to count
    if (begin == end)
        return 0;
    else // note the pre-increment here. post-increment won't work.
        return 1 + count_characters(++begin, end);
}

可以像这样使用:

std::string foo = "a phrase, yay";
std::cout << count_characters(foo.begin(), foo.end());

作为奖励,它可用于任何其他简单容器...... vectorset charstring一样有效这里,因为迭代器提供了一种很好的通用方法来处理容器。然而,这个设施可能对这个特定的家庭作业问题不感兴趣。

一个函数,不需要包装器或传递多余的参数。如果你将这种情况复制到你交付的工作中,要小心;如果你不理解template,这将是一个轻率剽窃的确定标志; - )