アルゴリズム ・ Chapter 26

【再帰】

記事 ・ 冒頭を無料公開中

ここまでの道具は「データの持ち方」の話でした。この章は少し毛色が変わって、「処理の組み立て方」の話です。再帰とは、関数が、自分自身を呼ぶこと。初見では頭がねじれる感覚があるはずですが、仕組みは意外なほど単純で、しかもその仕組みはすでに学んだスタックの上に乗っています。

再帰とは

理屈より先に、動くものを見ます。カウントダウンする関数です。

出力は 3、2、1、発射!となります。流れを追うと、

countdown(3)が3を表示してcountdown(2)を呼ぶ→

countdown(2)が2を表示してcountdown(1)を呼ぶ→

countdown(1)が1を表示してcountdown(0)を呼ぶ→

countdown(0)は「発射!」を出してreturn(もう自分を呼ばない)。

関数が自分を呼ぶたびに、問題(n)がひとつ小さくなり、最後に止まる。これが再帰の全体像です。

再帰の2つの部品

すべての再帰は、この2つでできています。

①ベースケース(止まる条件): if (n === 0) return; の部分。「これ以上小さくしなくていい、ここで終わり」という出口です。必ず関数の先頭に書きます。

②再帰ステップ(小さくして自分を呼ぶ): countdown(n - 1) の部分。必ず、問題を小さくしてから呼びます(nのままで呼んだら永遠に終わりません)。

逆に言うと、再帰のバグは必ずこのどちらかです。出口がない、または小さくなっていない。では、出口がないと何が起きるのか。見ておきましょう。

▶ 実行してみよう(わざと壊す)

エラーが出ます。「Maximum call stack size exceeded」(コールスタックの上限を超えました)。スタックの章で、「関数を呼ぶたびに『戻り先の記録』がスタックに積まれる」と話しました。自分を呼ぶたびに記録が1枚積まれ、誰もreturnしないので誰も降りてこない。積み上がり続けた呼び出しの塔が、上限に達して崩れた。それがこのエラーの正体です。再帰はスタックの上で動いています。だからこのエラーを「スタックオーバーフロー」と呼びます。

戻り値を組み立てる再帰

countdownは表示するだけでした。再帰の本領は、戻り値を積み上げて答えを組み立てる形です。定番の例、階乗(nの階乗 = 1×2×…×n)で見ます。

factorial(4) の中身を展開すると、

4 × factorial(3) →

4 × (3 × factorial(2)) →

4 × (3 × (2 × factorial(1))) →

4 × 3 × 2 × 1 = 24。

このチャプターの続きは受講生限定です

本文の残り、図解・実行できるコードブロック・演習はプラン加入後に読めます。

料金プランを見る