通过递归以相反的顺序打印出一行中的单词
Print out the words of a line in reverse order through recursion
我尽量不使用任何存储容器。我不知道这是否可能。这是我迄今为止所拥有的。(我有一个分段错误)。
#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
- 如何阅读两个单词,然后阅读C++中的一行?
- 从文件的一行中查找数字的平均值,避免使用第一个单词
- 迭代一行(字符串)C++ 中的每个单词
- 从一个段落到另一个段落,从一行到另一行阅读单词(C++)
- 如何在Visual Studio 2013 Ultimate Edition中包含某个单词的每一行中插入断点
- 在一行中输入具有其他输入类型的多个单词字符串
- 如何在文本文件中仅读取一行,该文本文件使用QT具有特定单词
- 在输出时,我对如何将数量和单词组合在一行感到非常困惑
- 如何一次一个单词而不是一行一行地消除错误输入
- C++在文件中的一行中搜索某些单词,然后在这些单词后面插入一个单词
- 什么是调试断言?如何将一行的单词放入数组中
- 计算一行中的 # 个单词
- 在c++中显示一行vs单词
- 你如何知道输入流何时到达一行中的最后一个单词
- 通过递归以相反的顺序打印出一行中的单词
- 如果一行包含某个单词,请保存它
- 在一行中出现一个单词
- 如何从.txt文件复制单词到数组.然后将每个单词打印在单独的一行上
- 在一行最后一个单词之后立即退出While循环
- C++ 我们如何从文本文件中查找单词的每一行