0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Recursion(再帰)を理解する

Posted at

再帰関数とは

自分自身を呼び出す関数のこと。ループと似ており同じコードを何度も実行するので、無限再帰を防ぐための条件が必要になる。

再帰のコードを書くときのポイント

  • 実際の値を当てはめて、コードの流れを考える
  • どのような関数をどこで呼び出すか考える
  • ベースケースとリカーシブケースを考える
  • 「リカーシブケース」・・・何を対象に再帰処理を継続していくか(ループの繰り返し処理にあたる部分)
  • 「ベースケース」・・・どういう条件を満たしたら再帰処理を止めるのか(ループ終了)
  • 木構造で考えると分かりやすい

実際にコードを分解してみる

  • じゃんけんの組み合わせ(下のサイトからコード参照)

const rockPaperScissors = (rounds = 3) => {
  let out = [];
  const weapons = ["rock", "paper", "scissors"];
  const play = (rounds, result = []) => {
    // exit case
    if (rounds < 1) {
      out.push(result);
      return;
    }
    // recursive case
    for (let i = 0; i < weapons.length; i++) {
      const weapon = weapons[i];
      play(rounds - 1, result.concat(weapon));
    }
  };
  play(rounds);
  return out;
};
  • 分解して考えると・・・
rockPaperScissors(); //関数呼び出しすると・・・

// 大前提 = すべてのループは3回ずつ回ること!!!

play(3, []); //rounds = 3

// loop 0 (i = 0 --> "rock") 親のループが始まる
weapon = "rock";
play(2, result = ["rock"]);

// loop 0-0 (i = 0 --> "rock") 親のループの中で、子のループが始まる
weapon = "rock";
play(1, result = ["rock", "rock"]);

// loop 0-0-0 (i = 0 --> "rock") 子のループの中で、孫のループが始まる
weapon = "rock";
play(0, result = ["rock", "rock", "rock"]);
//exit case === True
out = [["rock", "rock", "rock"]];
return 
//つまり「処理の終了」、孫のループの値が更新される。
play(0, result = ["rock", "rock", "rock"]);

// loop 0-0-1 (i = 1 --> "paper")
weapon = "paper";
play(0, result = ["rock", "rock", "paper"]);
//exit case === True
out = [["rock", "rock", "rock"], ["rock", "rock", "paper"]];
return 

// loop 0-0-2 (i = 2 --> "scissors")
weapon = "scissors";
play(0, result = ["rock", "rock", "scissors"]);
//exit case === True
out = [["rock", "rock", "rock"], ["rock", "rock", "paper"], ["rock", "rock", "scissors"]];
return 

// 孫のループがすべて回り切ったので、いったん子のループに戻る(子ループの値更新)
// loop 0-1 (i = 1 --> "paper")
weapon = "paper";
play(1, result = ["rock", "paper"]);

// また孫のループが始まる
// loop 0-1-0 (i = 0 --> "rock")
weapon = "rock";
play(0, result = ["rock", "paper", "rock"]);
//exit case === True
out = [["rock", "rock", "rock"], ["rock", "rock", "paper"], ["rock", "rock", "scissors"], ["rock", "paper", "rock"]];
return

// loop 0-1-1
// loop 0-1-2
// loop 0-2-0
// loop 0-2-1
// loop 0-2-2
// loop 1-0-0

以下省略・・・

動画

オススメしていただいた動画。解説が分かりやすかったです。

ひとこと

はじめて再帰のコードを一から書いたとき、再帰処理の流れより先に実行すべき関数ばかり考えて、手が止まってしまいました。その時に頂いたアドバイスが「再帰のコードを書くときのポイント」です。
何パターンかコードを見たり書いたりしているうちに処理の流れが理解できて、リファクタリングもできるようになりました。引き続き理解を深めていこうと思います!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?