为啥这段代码会继续(递归)?
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? [复制]