今回はメソッドが自分自身を呼び出す場合の再帰処理というものについて。
それでは早速いってみよー。
再帰処理とは?
再帰処理とは、メソッドの中でさらに同じメソッドを呼び出すことを指す。
例えばメソッドAがあるとする。
メソッドAの中でメソッドAを使用することを指す。
階乗の計算などで使用されることが多い。
階乗というのは「4!(4x3x2x1)」という形のこと。
高校の数学で習った記憶が・・・(中学だっけ?)
よく使用さる再帰処理の形
再帰処理としてよく目にする形は「return」を使用したもの。
if条件と使用されることが多い。
if条件については以下参照。
ifとelseを使った条件構文 Javaプログラミング初心者の記録vol.18
以下が再帰処理の一般的な形。
メソッド名(引数){
if(条件){
return 返す値;
}
else{
return メソッド名(引数)
}
どのような処理になるのかは実際にコードを見たほうが分かりやすい。
再帰処理を利用したコード(メソッドのみ)
以下のコードは再帰処理の部分のみをピックアップしたもの。
例えば「saiki」という名前のメソッドを作ったとする。
自分で作るメソッドについては以下参照。
自分で作ったクラスの中にメソッドを作る方法 by Javaプログラミング初心者 Vol.40
static int saiki(int n){
if(n<=0){
return 1;
}
else{
return saiki(n-1)*n;
}
}
「saiki」メソッドの中に「if-else条件構文」があり、さらにelseの中に「saikiメソッド」を呼び出している。
プログラムの処理順番
プログラムがどういうように処理されているかを追ってみる。
最初のメソッドで「saiki(int n)」となっている。
この「n」に「5」という数字を入れたとして順番に処理を追っていく。
(この「5」と設定するのはメインメソッドの中で行われる)
nが5として指定された場合
saiki(int 5)の処理
- 「n」が「5」と指定された。
- if処理を行う。
- ()内の「n<=0(5は0より小さい)」というのは間違っている。
- else内の処理へ。
- 「saiki(n-1)*n」の「saiki(n-1)」の部分でsaikiメソッドが呼び出されている。
「saiki(n-1)*n」はsakiメソッドに「n」を掛ける(掛け算)ということ。
そのため「saiki(n-1)」の時点で「saikiメソッド」が呼び出されていることになる。
メソッドが呼び出されると、そのメソッド内の処理が行われる。
- nは「5」のため「saiki(5-1)*5」で「saiki(4)*5」となる。
ここで一旦「n」が「5」だった場合の処理が終わった。
ここでポイントなのが、「(4)*5」の計算が行われる前に「saikiメソッド」が呼び出されているということ(saiki(n-1)*n)。
この()は「先に計算してほしい」という()ではなく、saiki()メソッドの()ということに注意。
saiki(4)の処理
saikiメソッドがelse内で呼び出され、「saiki(n-1)」となっていることから()内が「4」になったsaikiメソッド内の処理が行われる。
- メソッドの引数部分の()内が「4」になったことで、nの値は「4」となった。
- if処理を行う。
- ()内の「n<=0(4は0より小さい)」というのは間違っている。
- else内の処理へ。
- 「saiki(n-1)*n」の「saiki(n-1)」の部分でsaikiメソッドが呼び出されている。
- nは「4」のため「saiki(4-1)*4」となる。
「n」が「4」の時の処理が終わった。
ここで「n」が「5」だった場合の処理内容を思い出す。
「n」が「5」のときの処理結果は「saiki(4)*5」だった。
この「saiki(4)」という部分が「n」が「4」の時の処理内容になる。
「n」が「5」のときと「n」が「4」の時の処理結果を合わせると、「saiki(4-1)*4*5」となるのがわかるだろうか。
「saiki(4)*5」の「saiki(4)」の部分(「n」が「4」の時)に「saiki(4-1)*4」を代入しただけ。
こう考えると少しは再帰処理について分かると思う。
この処理をメソッドが呼び出されなくなるまでずっと繰り返していく。
saiki(3)の処理
saikiメソッドがelse内で呼び出され、「saiki(n-1)」となっていることから()内が「3」になったsaikiメソッド内の処理が行われる。
- メソッドの引数部分の()内が「3」になったことで、nの値は「3」となった。
- if処理を行う。
- ()内の「n<=0(3は0より小さい)」というのは間違っている。
- else内の処理へ。
- 「saiki(n-1)*n」の「saiki(n-1)」の部分でsaikiメソッドが呼び出されている。
- nは「3」のため「saiki(3-1)*3」となる。
「n」が「3」の時の処理が終わった。
「n」が「5」の時、「n」が「4」の時、そして「n」が「3」の時の処理結果を合わせると、「saiki(3-1)*3*4*5」となる。
次はsaiki(2)が呼び出された。
saiki(2)の処理
saikiメソッドがelse内で呼び出され、「saiki(n-1)」となっていることから()内が「2」になったsaikiメソッド内の処理が行われる。
- メソッドの引数部分の()内が「2」になったことで、nの値は「2」となった。
- if処理を行う。
- ()内の「n<=0(2は0より小さい)」というのは間違っている。
- else内の処理へ。
- 「saiki(n-1)*n」の「saiki(n-1)」の部分でsaikiメソッドが呼び出されている。
- nは「2」のため「saiki(2-1)*2」となる。
「n」が「2」の時の処理が終わった。
「n」が「5」の時、「n」が「4」の時、「n」が「3」の時、そして「n」が「2」の時の処理結果を合わせると、「saiki(2-1)*2*3*4*5」となる。
saiki(1)が呼び出された。
saiki(1)の処理
saikiメソッドがelse内で呼び出され、「saiki(n-1)」となっていることから()内が「1」になったsaikiメソッド内の処理が行われる。
- メソッドの引数部分の()内が「1」になったことで、nの値は「1」となった。
- if処理を行う。
- ()内の「n<=0(1は0より小さい)」というのは間違っている。
- else内の処理へ。
- 「saiki(n-1)*n」の「saiki(n-1)」の部分でsaikiメソッドが呼び出されている。
- nは「1」のため「saiki(1-1)*1」となる。
「n」が「1」の時の処理が終わった。
「n」が「5」の時、「n」が「4」の時、「n」が「3」の時、「n」が「2」、そして「n」が「1」の時の処理結果を合わせると、「saiki(1-1)*1*2*3*4*5」となる。
saiki(0)が呼び出された。
saiki(0)の処理⇒メソッドの呼び出しの終わり
saikiメソッドがelse内で呼び出され、「saiki(n-1)」となっていることから()内が「0」になったsaikiメソッド内の処理が行われる。
- メソッドの引数部分の()内が「0」になったことで、nの値は「0」となった。
- if処理を行う。
- ()内の「n<=0(0は0より小さい、もしくは同じ)」というのは合っている。
- if内の処理へ。
- 条件に合っている場合、「return 1」ということから処理は「1」という結果になるということ。
- 呼び出されるメソッドはない。
「n」が「0」の時の処理が終わった。
「n」が「5」の時、「n」が「4」の時、「n」が「3」の時、「n」が「2」、そして「n」が「1」の時の処理結果を合わせると、「1*1*2*3*4*5」となる。
階乗の特質で、0以下の数字の場合は計算結果は「1」になる。
ここで出てくるのが「return」。
「return」はsaiki()メソッド(今回はnが「5」の場合)に「1*1*2*3*4*5」の計算結果を返すというもの。
「1*1*2*3*4*5」の計算結果の「120」というデータをsaiki()メソッドが持っているということになる。
再帰処理を利用したコード(完全版)
public class SaikiShori {
public static void main(String[] args) {
System.out.println(“再帰処理の結果:”+SaikiShori.saiki(5));
}
static int saiki(int n) {
if(n<=0) {
return 1;
}
else {
return saiki(n-1)*n;
}
}
}
以上を実行すると以下の結果が得られる。
ピンクのアンダーラインを引いている部分が再帰処理。
数字を指定するのは「SaikiShori.saiki(5)」の部分。
saiki()メソッドの部分で「saiki(int n)」と書いている。
このことからメインメソッドでsaiki()メソッドを呼び出す際は「int n」の部分の()内に数字を指定することで自分の好きな数字の階乗の結果を得られる。
自分で作成したメソッドの呼び出しについては以下参照。
自分で作ったメソッドをオブジェクトを作って呼び出す by Javaプログラミング初心者 Vol.41
大きい数字を入力したいときは「int」だと計算結果がintの使用できる数字の範囲に収まらない場合がある。
大きい数字を入力することを想定するなら「long」を使用する。
intとlongの数字の範囲については以下参照。
変数の型の種類について今更まとめてみた Javaプログラミング初心者の記録vol.25
最後に
理解するのにとても苦労したけれど、処理を一個一個追っていくことでちゃんと頭の中で理屈が理解できたと思う。
始めはreturnを使用するのが再帰処理かと思ったけれど、メソッドの中で同じメソッドを呼び出すことが再帰処理ということを途中から理解し始めた私・・・。
コメント