【问题标题】: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 你能解释一下这里发生了什么吗(把它作为答案发布,这样我就可以接受它,也许它会帮助其他人)
  • 你没有定义你的基本情况

标签: java recursion return return-value


【解决方案1】:

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

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

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

  1. check("AA") 运行第一个 println,然后运行 ​​check("A")
  2. check("A") 也运行第一个 println,此时条件阻止了进一步的递归,所以执行到第二个 println 语句
  3. 函数调用返回,现在我们回到 check("AA") 调用,在检查函数之后的行中
  4. 执行继续,您会看到第二个 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】:

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

          1. 如果字符串为空 - 没关系
          2. 如果不是,请检查第一个字符:
            • 如果不是“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 函数时,它会创建一个新的递归调用,该调用在堆栈中与其变量一起排队。当它返回结果时,您只是忽略了它(没有存储结果)。要使用最低级别递归函数的值,您需要将其值传递回其父递归调用。所以最后你得到了结果。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-02-03
            • 1970-01-01
            • 2019-10-28
            • 2014-12-07
            • 2015-03-26
            • 2018-10-28
            • 2013-04-27
            相关资源
            最近更新 更多