通过递归以相反的顺序打印出一行中的单词

Print out the words of a line in reverse order through recursion

本文关键字:单词 一行 打印 递归 顺序      更新时间:2023-10-16

我尽量不使用任何存储容器。我不知道这是否可能。这是我迄今为止所拥有的。(我有一个分段错误)。

#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;
}

我知道这个代码可能有很多错误。所以撕扯吧。我渴望学习。我正试图模仿订单后打印,就像你在反向打印单链表时所做的那样。谢谢

编辑:例如:"你很了不起"变成了"你很神奇"

segfault是堆栈溢出。

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
}

问题是递归一直持续到内存耗尽。注意这一行:

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;
}

递归的一种方法是在函数参数中累积结果,可以允许编译器自动转换为迭代。如果你已经用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(" nrt");
    // 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   difficultn testcase   ") << std::endl;
    return 0;
}

我试图通过使用标准算法来做一个简短的例子。我还处理了更多种类的空格,而不仅仅是标准的空格(例如制表符)。

#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                                                                          

关键在于在擦除语句中将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,这样就不需要创建临时变量。在线试用。

#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;
}

问题是,您没有对最后一个单词做任何事情,也没有对剩余的块做任何事情。

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

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;
}

Videone