これは、ソースリストを長くすると実際に視覚化するのが簡単になると思います。を使用する[0, 1, 2]
と、再帰呼び出しによってリストの最後の項目が繰り返し切り捨てられることがわかります。つまり、recusionは、次のような再帰呼び出しのスタックを構築します。
genSubsets([0,1,2])
genSubsets([0,1])
genSubsets([0])
genSubsets([])
この時点で、再帰的アルゴリズムの「基本ケース」に到達します。この関数の基本的なケースは、パラメーターとして指定されたリストが空の場合です。基本ケースをヒットすると、空のリストを含むリストが返されます[[]]
。スタックが戻ったときの外観は次のとおりです。
genSubsets([0,1,2])
genSubsets([0,1])
genSubsets([0]) <- gets [[]] returned to it
そのため、戻り値は前のレベルに戻り、smaller
変数に保存されます。変数extra
は、リストの最後の項目(この場合はコンテンツ全体)のみを含むスライスに割り当てられます[0]
。
ここで、ループはの値を繰り返し処理し、それらの連結をにsmaller
追加します。(空のリスト)には値が1つしかないため、値も1つだけになります。これはです。これは、ある時点で印刷している値だと思います。extra
new
smaller
new
[]+[0]
[0]
次に、最後のステートメントはとの連結を返すsmaller
ためnew
、戻り値は[[],[0]]
です。スタックの別のビュー:
genSubsets([0,1,2])
genSubsets([0,1]) <- gets [[],[0]] returned to it
戻り値はsmaller
再び割り当てられ、extra
は[1]
であり、ループが再び発生します。今回は、new
2つの値を取得[1]
します[0,1]
。それらは再び最後に連結されsmaller
、戻り値は[[],[0],[1],[0,1]]
です。最後のスタックビュー:
genSubsets([0,1,2]) <- gets [[],[0],[1],[0,1]] returned to it
同じことが再び起こりますが、今回2
はこれまでに見つかった各アイテムの最後にsを追加します。new
として終わります[[2],[0,2],[1,2],[0,1,2]]
。
最終的な戻り値は[[],[0],[1],[0,1],[2],[0,2],[1,2],[0,1,2]]