递归不使用循环。
因此,如果您的函数名为 rfind(...),那么在 rfind 中您必须完成以下所有 3 项:
没有找到就终止 -- 确定您已经到达 str 的开头,然后以 nullptr 退出
以 find 结束——在 str 中的某个位置识别“ch”,然后退出返回该位置(一个 char*)
继续搜索 -- 通过递归调用 rfind(...),并返回递归调用返回的值。
edit - 只是为了好玩,这里有一个 3 参数 rfind 我认为更具可读性
注意:没有循环、退出情况和尾递归。
// find _last_ occurrance of ch in str, starting at indx
char* rfind(char* str, char ch, int indx)
{
// Req 1: terminate when not found, return nullptr
if(indx < 0) return (nullptr);
// Req 2: terminate when found, return char*
if(ch == str[indx]) return(&str[indx])
// Req 3: continue search, return search results
return ( rfind (str, ch, (indx-1)) ); // keep looking
}
[去掉-3参数rfind用法]
编辑 - 为了完成这个版本,我提供以下内容。结果包括
a) 2个参数rfind,
b) 尾递归,
c) 一些测试代码
我以随意阅读的形式呈现以下内容。您必须添加前向声明或适当地重新安排代码以进行编译。
test_rfind() 的用法:
注意 test_rfind() 有 2 个参数传入 rfind()
int t122()
{
char str[] = "t123abcdefg*o4";
size_t strSize = strlen(str);
std::cout << "\n strSize = " << strSize << " " << (void*)str
<< "\n 01234567890123" << std::endl;
for (size_t i = 0; i < strSize; ++i) {
test_rfind(str, str[i]);
}
test_rfind(str, 'z');
test_rfind(str, '0'); // digit '0'
test_rfind(str, 'K');
// ...
}
test_rfind 调用 rfind(),
并筛选出 null str 和 null tgt 为测试用户提供反馈:
void test_rfind(char* str, char tgt)
{
do // not part of the recursion, not really a loop, just a test simplification
{
if (0 == str) { std::cout << " str is null " << std::endl; break; }
// ===================================================================
char* pos = rfind(str, tgt); // 2 parameter invocation - see below
// ===================================================================
if (nullptr == pos) {
std::cout << "rfind('" << std::setw(14) << str
<< "', '" << tgt << "') : "
<< " char '" << tgt
<< "' not found" << std::endl;
break;
}
// else found
std::cout << "rfind('" << std::setw(14) << str
<< "', '" << tgt << "') = "
<< (void*)pos
<< std::setw(20) << pos
<< " last '" << pos[0]
<< "' at indx: " << (pos - str) << std::endl;
}while(0);
}
这是您需要的 2 参数 rfind()。
惊喜!它只是做一些验证,然后使用现有的 3 参数 rfind()。
// two parameter
char* rfind(char* str, char tgt)
{
// pre-validation
if (0 == str) return(nullptr); // one null check here, rather than 'inside' recursion
// pre-validation - tbr: check range (0 <= char <= 127)
// allow (0 == tgt): a char can be 0
// now use the 'just for fun' 3 parameter rfind
return ( rfind(str, tgt, strlen(str)) ); // use tail recursion
}
我发现这种在递归过程中的“中间步骤”处理了几个前(有时是后)验证。这样可以避免这些事情使实际的递归函数复杂化。
第 3 个参数 rfind() 位于此答案的开头附近,并且未更改。
猜猜看——它提供了一个通常必要的功能:在字符串中查找最后一个目标字符,但是您可以在字符串中的任何位置开始搜索。这样,如果您的字符串有 2 个 tgt 字符 - 您使用 2 个参数 rfind() 找到最后一个 ch,然后使用第 3 个参数(而不是缩短 str)找到那个之前的 tgt。
注意:当两个函数的签名是唯一的时,C++ 允许两个函数具有相同的标识符。因此 2 参数和 3 参数版本共享名称“rfind()”。
测试结果:
strSize = 14 0xbff8f4bd
01234567890123
rfind('t123abcdefg*o4', 't') = 0xbff8f4bd t123abcdefg*o4 last 't' at indx: 0
rfind('t123abcdefg*o4', '1') = 0xbff8f4be 123abcdefg*o4 last '1' at indx: 1
rfind('t123abcdefg*o4', '2') = 0xbff8f4bf 23abcdefg*o4 last '2' at indx: 2
rfind('t123abcdefg*o4', '3') = 0xbff8f4c0 3abcdefg*o4 last '3' at indx: 3
rfind('t123abcdefg*o4', 'a') = 0xbff8f4c1 abcdefg*o4 last 'a' at indx: 4
rfind('t123abcdefg*o4', 'b') = 0xbff8f4c2 bcdefg*o4 last 'b' at indx: 5
rfind('t123abcdefg*o4', 'c') = 0xbff8f4c3 cdefg*o4 last 'c' at indx: 6
rfind('t123abcdefg*o4', 'd') = 0xbff8f4c4 defg*o4 last 'd' at indx: 7
rfind('t123abcdefg*o4', 'e') = 0xbff8f4c5 efg*o4 last 'e' at indx: 8
rfind('t123abcdefg*o4', 'f') = 0xbff8f4c6 fg*o4 last 'f' at indx: 9
rfind('t123abcdefg*o4', 'g') = 0xbff8f4c7 g*o4 last 'g' at indx: 10
rfind('t123abcdefg*o4', '*') = 0xbff8f4c8 *o4 last '*' at indx: 11
rfind('t123abcdefg*o4', 'o') = 0xbff8f4c9 o4 last 'o' at indx: 12
rfind('t123abcdefg*o4', '4') = 0xbff8f4ca 4 last '4' at indx: 13
rfind('t123abcdefg*o4', 'z') : char 'z' not found
rfind('t123abcdefg*o4', '0') : char '0' not found
rfind('t123abcdefg*o4', 'K') : char 'K' not found
我最近对递归代码的 -O3 优化印象深刻。