簡體   English   中英

為什么此代碼繼續(遞歸)?

[英]Why does this code continue (recursion)?

首先,我想說的是,我知道這是解決我的問題的最糟糕的方法,但是我只想熟悉遞歸。 我想檢查一個序列是否為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后,代碼應該已停止。 出了什么問題以及如何解決此問題?

沒關系。 您所謂的“保持運行狀態”就是遞歸的工作方式。 如果您看過初始電影,可以作為一個比喻來幫助您。

函數會多次調用自身(您的第一個println語句對此進行了標記),然后在某種程度上滿足了遞歸結束條件后,函數會將執行返回到調用堆棧幀(這是第二個println捕獲的幀)。

使用“ AA”的簡單示例:

  1. check(“ AA”)運行第一個println,然后運行check(“ A”)
  2. check(“ A”)也運行第一個println,當時條件阻止進一步遞歸,因此執行繼續到第二個println語句
  3. 函數調用返回,現在我們返回到check函數后面的行中的check(“ AA”)調用
  4. 執行繼續,您會看到第二個println指向結果

PS您遇到的一個問題是忽略該函數的返回結果。

您放棄對check的遞歸調用的結果。 因此,即使支票返回false ,信息也會丟失。 並且由於在其中調用check的分支永遠不會設置correct因此它將保留其初始化值( true )。

據我一眼就能看出,解決方案就像分配correctcheck返回值一樣簡單。

您沒有檢查它是否返回false 您需要創建一個if語句,以在check()返回false時結束方法

只需打電話

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

您正在執行所需的操作,但是當遞歸返回時,該方法將繼續運行(如您在輸出中字符串“增長”時所見)。

如果增加使用

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

或者可能

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

您可能會得到所需的輸出。 您可以使用調試器來診斷哪個更有意義

遇到錯誤字符時,您沒有條件終止。 適當的遞歸方法如下:

  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));
}

您只需要更改線

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) { 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 (seq.substring(0, seq.length() - 1).length() > 0) { return check(seq.substring(0, seq.length() - 1)); }這會使您的檢查結果返回上一級遞歸函數,

最后是理想的結果。

為什么需要返回檢查功能?

當您在if check內部調用check函數時,會創建一個新的遞歸調用,該調用及其變量在堆棧中排隊。 當它返回結果時,您只是忽略了它(沒有存儲結果)。 要使用最低級別的遞歸函數的值,您需要將其值傳遞回其父遞歸調用。如此一來,您最終得到結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM