为啥这段代码会继续(递归)?

Posted

技术标签:

【中文标题】为啥这段代码会继续(递归)?【英文标题】:Why does this code continue (recursion)?为什么这段代码会继续(递归)? 【发布时间】:2017-04-18 04:56:50 【问题描述】:

首先我想说我知道这是解决我的问题的最糟糕的解决方案,但是我只想熟悉递归。我想检查一个序列是否是 DNA(所以它只能包含 A、T、G 或 C)。我的代码:

public Boolean check(String seq) 
    System.out.println(seq);
    Boolean correct = true;
    Character letter = seq.charAt(seq.length() - 1);
    if ("ATGC".contains(letter.toString())) 
        if (seq.substring(0, seq.length() - 1).length() > 0) 
            check(seq.substring(0, seq.length() - 1));
        

     else 
        correct = false;

    
    System.out.println(seq + " " + correct);
    return correct;

但是,当我运行代码时,它会在更改 correct = false 后继续运行。为了清楚起见,我将粘贴打印语句的输出:

ATXGCTGC
ATXGCTG
ATXGCT
ATXGC
ATXG
ATX
ATX false
ATXG true
ATXGC true
ATXGCT true
ATXGCTG true
ATXGCTGC true

返回的布尔值是true,但是代码应该在ATX false 之后停止。 什么出了问题,如何解决这个问题?

【问题讨论】:

你试过return-ing递归调用吗? 哇,原来是这个问题哈哈哈,谢谢! @cricket_007 你能解释一下这里发生了什么吗(把它作为答案发布,这样我就可以接受它,也许它会帮助其他人) 你没有定义你的基本情况 【参考方案1】:

没关系。你所说的“保持运行”就是递归的工作原理。如果你看过《盗梦空间》这部电影可以作为一个比喻来帮助你。

Functions 多次调用自身(您的第一个 println 语句标记了这一点),然后一旦在某个级别满足递归结束条件,函数将执行返回到调用堆栈帧(这是由您的第二个println)。

用一个更简单的“AA”示例:

    check("AA") 运行第一个 println,然后运行 ​​check("A") check("A") 也运行第一个 println,此时条件阻止了进一步的递归,所以执行到第二个 println 语句 函数调用返回,现在我们回到 check("AA") 调用,在检查函数之后的行中 执行继续,您会看到第二个 println 指向结果

附:您遇到的一个问题是您忽略了函数的返回结果。

【讨论】:

【参考方案2】:

您丢弃了对check 的递归调用的结果。因此,即使检查返回false,该信息也会丢失。而且由于调用check 的分支永远不会设置correct,它将保留其初始化值(true)。

据我快速了解,解决方案就像将 correct 分配给 check 的返回值一样简单。

【讨论】:

【参考方案3】:

您没有检查它是否返回了false。当check() 返回false 时,您需要创建一个结束方法的 if 语句

【讨论】:

【参考方案4】:

只需调用

check(seq.substring(0, seq.length() - 1));

您正在做您想做的事,但是当该递归返回时,该方法继续耗尽(正如您在输出中看到字符串“增长”时所看到的那样)。

如果你增加使用

return check(seq.substring(0, seq.length() - 1));

或许

correct = check(seq.substring(0, seq.length() - 1));

你可能会得到你想要的输出。您可以使用调试器来诊断哪个更有意义

【讨论】:

【参考方案5】:

遇到错误字符时,您没有条件终止。适当的递归方法如下:

    如果字符串为空 - 没关系 如果不是,请检查第一个字符: 如果不是“ATGC”字符之一,则返回 false 如果是,则递归地将算法应用于从第二个字符开始的子字符串:

private static Set<Character> LEGAL_CHARS = 
    new HashSet<>(Arrays.asList('A', 'T', 'G', 'C'));

public boolean check(String seq) 
    if (seq.isEmpty()) 
        return true;
    
    if (!LEGAL_CHARS.contains(seq.charAt(0))) 
        return false;
    
    return check(seq.substring(1));

【讨论】:

这看起来比我的代码更简洁明了!谢谢你的建议!【参考方案6】:

你只需要换行

if (seq.substring(0, seq.length() - 1).length() > 0) check(seq.substring(0, seq.length() - 1));

if (seq.substring(0, seq.length() - 1).length() > 0) return check(seq.substring(0, seq.length() - 1)); 这会将您的检查结果返回到上层递归函数,

这到底是想要的结果。

为什么需要返回校验功能?

当您在 if check 中调用 check 函数时,它会创建一个新的递归调用,该调用在堆栈中与其变量一起排队。当它返回结果时,您只是忽略了它(没有存储结果)。要使用最低级别递归函数的值,您需要将其值传递回其父递归调用。所以最后你得到了结果。

【讨论】:

以上是关于为啥这段代码会继续(递归)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这段代码会进入无限循环? [复制]

为啥这段代码会导致访问不正确? [关闭]

函数指针 - 为啥这段代码会崩溃?

为啥这段代码会引发 SettingWithCopyWarning? [复制]

为啥这段代码会导致 Windows Defender 发疯,并将这段代码识别为名为 Ludicrouz.j 的木马

为啥这段代码会消耗这么多堆?