满足动态条件时退出递归函数
Quit recursive function when a dynamic condition is met
使用生成汉明距离内的所有位序列 t 中的函数:
void magic(char* str, int i, int changesLeft) {
if (changesLeft == 0) {
printf("%sn", str);
return;
}
if (i < 0) return;
// flip current bit
str[i] = str[i] == '0' ? '1' : '0';
magic(str, i-1, changesLeft-1);
// or don't flip it (flip it again to undo)
str[i] = str[i] == '0' ? '1' : '0';
magic(str, i-1, changesLeft);
}
我想退出递归函数并在发生某种情况时返回调用者函数(如果确实如此)。所以就像我的递归函数听到可能告诉她退出的声音一样!
它仅在打印str
后发生,如下所示:
if (changesLeft == 0) {
printf("%sn", str);
int quit_now = voices(str);
return;
}
如何做到这一点(停止展开递归并返回函数调用者)?
尝试:
if (i < 0 || quit_now == 1) return;
只是似乎阻止了执行并且永无止境!
PS - 我什至对 c 旧方法感兴趣。
鉴于函数当前没有返回值,一个简单的解决方案是使用它来指示是否满足该终止条件。 然后,如果结果变为 true,您可以使用它立即退出所有递归调用。
不确定我是否在这里正确捕获了您的预期逻辑,但直观的方法是这样的:
int magic(char* str, int i, int changesLeft) {
int result;
if (changesLeft == 0) {
printf("%sn", str);
return voices(str);
}
if (i < 0) return 0;
// flip current bit
str[i] = str[i] == '0' ? '1' : '0';
result = magic(str, i-1, changesLeft-1);
if( !result ) {
// or don't flip it (flip it again to undo)
str[i] = str[i] == '0' ? '1' : '0';
result = magic(str, i-1, changesLeft);
}
return result;
}
用最简单的形式来说,你可以做这样的事情:
void foo(bool & ret) {
// doStuff...
if (ret) return;
foo(ret);
// doStuff...
if (ret) return;
foo(ret);
}
然后启动递归:
bool ret = false;
foo(ret);
在您的情况下,您可以通过以下方式中断递归
if (!changesLeft) {
printf("%sn", str);
ret = true;
return;
}
设置为 true 将使您退出整个调用树。
你也可以用 C 语言做到这一点,只需使用指针而不是引用即可。
magic
函数在两个地方递归调用自身。 因此,在每个地方,您都需要检查退出条件。 帕迪给出的答案详细说明了这一点。
立即展开堆栈的另一种方法是使用setjmp
和longjmp
它们可以用作非本地goto
.
jmp_buf magic_buf;
void magic_int(char* str, int i, int changesLeft) {
if (changesLeft == 0) {
printf("%sn", str);
if (voices(str)) {
longjmp(magic_buf, 1);
}
return;
}
if (i < 0) return;
// flip current bit
str[i] = str[i] == '0' ? '1' : '0';
magic_int(str, i-1, changesLeft-1);
// or don't flip it (flip it again to undo)
str[i] = str[i] == '0' ? '1' : '0';
magic_int(str, i-1, changesLeft);
}
void magic(char* str, int i, int changesLeft) {
if (!setjmp(magic_buf)) {
magic(str, i, changesLeft);
}
}
setjmp
函数在直接调用时返回0
。 调用longjmp
时,实际返回的是setjmp
函数,返回值是给longjmp
的第二个参数。
在这里,我们有一个调用setjmp
的包装函数。 这将设置调用longjmp
时的跳转点。 然后调用递归函数。 稍后,当递归函数"听到声音"告诉它现在退出时,它会调用longjmp
,该调用立即直接进入相应的setjmp
调用。
这些功能在C99和POSIX中都有指定,因此符合POSIX的系统(即Linux)应该在C89模式下仍然可以使用这些功能。
如果要在C++中执行此操作,首选方法是在递归函数中抛出异常并在包装函数中捕获它。
struct magic_voices {
int rval;
};
void magic_int(char* str, int i, int changesLeft) {
if (changesLeft == 0) {
printf("%sn", str);
int rval = voices(str);
if (rval) {
struct magic_voices ex;
ex.rval = rval;
throw ex;
}
return;
}
if (i < 0) return;
// flip current bit
str[i] = str[i] == '0' ? '1' : '0';
magic_int(str, i-1, changesLeft-1);
// or don't flip it (flip it again to undo)
str[i] = str[i] == '0' ? '1' : '0';
magic_int(str, i-1, changesLeft);
}
void magic(char* str, int i, int changesLeft) {
try {
magic(str, i, changesLeft);
} catch (struct magic_voices ex) {
printf("rval=%dn", ex.rval);
}
}
这是一个非递归变体。基本上,它生成所有递增的序列0 <= a[0] < ... < a[dist-1] < strlen(num)
,并在相应的索引处还原位。
void print(const char* num, const vector<int>& a) {
size_t k = 0, n = strlen(num);
for (size_t i = 0; i < n; ++i)
if (k < a.size() && a[k] == i) {
cout << (num[i] == '0') ? '1' : '0';
++k;
}
else
cout << num[i];
cout << endl;
}
void hamming(const char* num, size_t dist) {
assert(dist > 0);
vector<int> a(dist);
size_t k = 0, n = strlen(num);
a[k] = -1;
while (true)
if (++a[k] > n - dist + k)
if (k == 0)
return;
else {
--k;
continue;
}
else
if (k == dist - 1) {
print(num, a);
// conditional return here
}
else {
a[k+1] = a[k];
++k;
}
}
可以这样使用:
int main()
{
hamming("0000", 2);
/* output:
1100
1010
1001
0110
0101
0011
*/
}
附言感谢@ruakh提到while - if
条件下缺少优化。
- 递归函数计算序列中的平方和(并输出过程)
- 如何在Elixir中调用递归函数并行
- 递归函数有效,但无法记忆
- 为什么我的递归函数按降序打印,然后按升序打印?
- 为什么递归函数的最终输出是 5?
- 有没有办法使用递归函数找到数组中最小值的 INDEX?C++
- 如何将记忆应用于此递归函数?
- 如何从递归函数中完全返回,该函数给出了每个函数结果的累积相加?
- 无穷大而循环时具有递归函数
- 即使没有调用这个递归函数,它是如何工作的?
- 如何使此递归函数从给定的起始位置返回最小的整数?
- 此递归函数的每次迭代的值存储在哪里?
- 可以清除递归函数中的变量吗?
- 如何在递归函数调用中返回当前函数值
- 递归函数 c++ 的复杂性
- 这个递归函数有什么作用?运行时的复杂性是多少?
- 任何人都可以查明我的递归函数中的错误吗?
- C++ 调试递归函数,它不会立即退出函数
- 满足动态条件时退出递归函数
- 霍夫曼解码中的递归函数不退出