使用Generate all sequences of bits within Hamming distance t中的功能:
void magic(char* str, int i, int changesLeft) {
if (changesLeft == 0) {
printf("%s\n", 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("%s\n", str);
int quit_now = voices(str);
return;
}
如何做到这一点(停止展开递归并返回函数调用者)?
尝试:
if (i < 0 || quit_now == 1) return;
似乎只是阻止执行而永远不会结束!
PS - 我甚至对c旧方法感兴趣。
答案 0 :(得分:3)
一个简单的解决方案,假设您的函数当前没有返回值,则使用它来指示是否满足该终止条件。然后,如果结果为真,您可以使用它立即退出所有递归调用。
我不确定我是否正确捕获了您预期的逻辑,但直观的方法是这样的:
int magic(char* str, int i, int changesLeft) {
int result;
if (changesLeft == 0) {
printf("%s\n", 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;
}
答案 1 :(得分:1)
magic
函数在两个地方递归调用自身。因此,在每个地方,您需要检查退出条件。 paddy给出的答案详述了这一点。
立即展开堆栈的另一种方法是使用setjmp
和longjmp
作为非本地goto
。
jmp_buf magic_buf;
void magic_int(char* str, int i, int changesLeft) {
if (changesLeft == 0) {
printf("%s\n", 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
时的跳转点。然后调用递归函数。后来,当递归函数&#34;听到声音&#34;告诉它退出现在,它会调用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("%s\n", 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=%d\n", ex.rval);
}
}
答案 2 :(得分:1)
以最简单的形式,你可以做这样的事情:
void foo(bool & ret) {
// doStuff...
if (ret) return;
foo(ret);
// doStuff...
if (ret) return;
foo(ret);
}
然后启动递归:
bool ret = false;
foo(ret);
在您的情况下,您可以通过
中断递归if (!changesLeft) {
printf("%s\n", str);
ret = true;
return;
}
设置为true将使您脱离整个调用树。
您也可以在C中执行此操作,只需使用指针而不是引用。
答案 3 :(得分:1)
这是一种非递归变体。基本上,它生成所有递增的序列intializeGame
,并在相应的索引处恢复位。
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;
}
}
P.S。感谢 @ruakh 提及int main()
{
hamming("0000", 2);
/* output:
1100
1010
1001
0110
0101
0011
*/
}
条件中缺少的优化。