通过递归以相反的顺序打印出一行代码

时间:2015-12-03 12:28:46

标签: c++

我试图不使用任何存储容器。我不知道它是否可能。这是我到目前为止所拥有的。 (我得到了分段错误)。

#include <iostream>
#include <string>

using namespace std;

void foo(string s)
{
    size_t pos;
    pos = s.find(' ');
    if(pos == string::npos)
        return;
    foo(s.erase(0, pos));
    cout << s.substr(0, pos) << " ";
}

int main()
{
    foo("hello world");
    return 0;
}

我知道这段代码可能有很多问题。撕掉了。我渴望学习。我正在尝试模仿订单打印,就像在单一链接列表的反向打印中一样。谢谢。

编辑: 一个例子: &#34;你太棒了&#34;成为&#34;令人惊讶的是你&#34;

6 个答案:

答案 0 :(得分:5)

段错误是堆栈溢出。

foo( "hello world" )将所有内容删除到第一个空格(" world")并进行递归。

foo( " world" )将所有内容删除到第一个空格(" world")并进行递归。

foo( " world" ) ...你明白了。

此外,一旦调用foo( s.erase( 0, pos ) ),在递归返回后尝试打印s.substr( 0, pos )没有意义。你需要在删除之前将子字符串保存在某个地方,这样你以后仍然需要打印它。

void foo(string s)
{
    size_t pos = s.find(' ');            // declare-and-use in one line
    string out = s.substr( 0, pos );     // saving the substring
    if ( pos != string::npos )
    {
        foo( s.erase( 0, pos + 1 ) );    // recurse, skipping the space...
        cout << " ";                     // ...but *print* the space
    }
    cout << out;                         // print the saved substring
}

答案 1 :(得分:4)

问题是你的递归会继续,直到内存不足为止。 请注意这一行:

if(pos == string::npos)

当你擦除子字符串时,你不会删除空格,所以在下一次递归中,s.find返回pos = 0,这意味着你的递归永远不会结束。

这是一个有效的代码。另请注意,我添加了一个级别变量,以便能够控制第一级的行为(在这种情况下添加endl

#include <iostream>
#include <string>

using namespace std;

void foo(string s, int l)
{
    size_t pos;
    pos = s.find(' ');
    if(pos == string::npos){
        cout << s << " ";
        return;
    }

    string temp = s.substr(0, pos);
    foo(s.erase(0, pos+1),l+1);
    cout << temp << " ";
    if(l == 0)
        cout << endl;
}

int main()
{
    foo("hello world", 0);
    return 0;
}

答案 2 :(得分:3)

递归方法(可能允许编译器自动转换为迭代)是将结果累积在函数参数中。如果您已经在任何Lisp语言系列中编写了递归函数,那将会很熟悉:

#include <iostream>
#include <string>

std::string reverse_words(const std::string& s, const std::string& o = {})
{
    using std::string;
    const auto npos = string::npos;

    static const string whitespace(" \n\r\t");
    // find start and end of the first whitespace block
    auto start = s.find_first_of(whitespace);
    if (start == npos)
        return s + o;
    auto end = s.find_first_not_of(whitespace, start);
    if (end == npos)
        return s + o;
    auto word = s.substr(0, start);
    auto space = s.substr(start, end-start);
    auto rest = s.substr(end);
    return reverse_words(rest, space + word + o);
}

int main()
{
    std::cout << reverse_words("hello to all the world") << std::endl;
    std::cout << reverse_words("  a more   difficult\n testcase   ") << std::endl;
    return 0;
}

答案 3 :(得分:2)

关键是在擦除语句中将1添加到pos。 所以试试:

#include <iostream>
#include <string>

using namespace std;

void foo(string s)
{
    size_t pos;
    pos = s.find(' ');
    if(pos == string::npos)
    {
        cout << s << " ";
        return;
    }
    string out = s.substr(0, pos);
    foo(s.erase(0, pos+1));
    cout << out << " ";
}

int main()
{
    foo("hello world");
    cout << endl;
    return 0;
}

修改

或者您可以使用char*而不是std::string,然后您不需要创建临时变量。试一试this SO answer

#include <iostream>
#include <cstring>

void foo(char* s)
{
    char* next = std::strchr(s, ' ');
    if(next != nullptr)
    {
        foo(next + 1);
        *next = 0;
    }
    std::cout << s << " ";
}

int main()
{
    char s[] = "You are amazing";
    foo(s);
    std::cout << std::endl;
}

答案 4 :(得分:2)

我尝试使用标准算法做一个简短的例子。我还处理更多种类的空间而不仅仅是标准空格(例如标签)。

#include <cctype>
#include <algorithm>
#include <iostream>
#include <string>

using namespace std;

void print_reverse(string words) {
  // Termination condition
  if(words.empty())
    return;

  auto predicate = (int(*)(int))isspace;
  auto sit = begin(words);
  auto wit = find_if_not(sit, end(words), predicate);
  auto nit = find_if    (wit, end(words), predicate);

  print_reverse(string(nit, end(words)));
  //      word                spaces
  cout << string(wit, nit) << string(sit, wit);
}

int main() {
  string line;
  getline(cin, line);
  print_reverse(line);
  cout << endl;
}

以下是一个示例运行:

$ ./print-out-the-words-of-a-line-in-reverse-order-through-recursion                         
You     are amazing                                                                          
amazing are     You                                                                          

答案 5 :(得分:1)

问题在于你没有用最后一个字做任何事情而且你没有对剩余的块做任何事情。

如果你有一台递归反向打印机,你会想要这样的东西(伪代码):

def recursive-reverse(string) {
  pos = string.find-last(" ");
  if pos doesn't exist {
    print string;
    return;
  } else {
    print string.create-substring(pos+1, string.end);
    recursive-reverse(string.create-substring(0, pos));
  }
}

在C ++中实现:

#include <iostream>
#include <string>

void recursive_reverse(std::string &s) {
  // find the last space
  size_t pos = s.find_last_of(" ");
  // base case - there's no space
  if(pos == std::string::npos) {
    // print only word in the string
    std::cout << s << std::endl;
    // end of recursion
    return;
  } else {
    // grab everything after the space
    std::string substring = s.substr(pos+1);
    // print it
    std::cout << substring << std::endl;
    // grab everything before the space
    std::string rest = s.substr(0, pos);
    // recursive call on everything before the space
    recursive_reverse(rest);
  }
}

int main() {
  std::string s("Hello World!");
  recursive_reverse(s);
  return 0;
}

ideone