满足动态条件时退出递归函数

时间:2016-11-28 00:17:47

标签: c++ c algorithm if-statement recursion

使用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 - 我甚至对旧方法感兴趣。

4 个答案:

答案 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给出的答案详述了这一点。

立即展开堆栈的另一种方法是使用setjmplongjmp作为非本地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 */ } 条件中缺少的优化。