質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

513閲覧

再帰的メソッドの変数の遷移を解説して欲しいです

gyro16

総合スコア89

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/12/30 03:09

編集2017/12/30 03:49

###前提・実現したいこと

このプログラムのrecur3(3)で実行したときの
do-while文でのswの遷移が掴めません。
特にdo-while文でswが2になるタイミングが分かりません。
解説してもらえる方お願いします。

do-while文内の
sw = sstk[ptr] + 1
この部分です。

sw == 2になる機序が分かりません。

やっていることは
public void recur3(int n){
recur3(n-1);
recur3(n-2);
System.out.println(n);
}

do-while文で
ptr--をやっているので
n = nstk[ptr] が範囲外IndexOutOfBoundsExceptionにならないかと思うんですが、
実行するとならない。

###発生している問題・エラーメッセージ

エラーメッセージ

###該当のソースコード

java

1import java.util.Scanner; 2 3class Recur3 { 4 5 static void recur3(int n) { 6 int[] nstk = new int[100]; 7 int[] sstk = new int[100]; 8 int ptr = -1; 9 int sw = 0; 10 11 while (true) { 12 if (n > 0) { 13 ptr++; 14 nstk[ptr] = n; 15 sstk[ptr] = sw; 16 17 if (sw == 0) 18 n = n - 1; 19 else if (sw == 1) { 20 n = n - 2; 21 sw = 0; 22 } 23 continue; 24 } 25 do { 26 n = nstk[ptr]; 27 sw = sstk[ptr] + 1; 28 ptr--; 29 30 if (sw == 2) { 31 System.out.println(n); 32 if (ptr < 0) 33 return; 34 } 35 } while (sw == 2); 36 } 37 } 38 39 public static void main(String[] args) { 40 Scanner stdIn = new Scanner(System.in); 41 42 System.out.print("整数を入力せよ:"); 43 int x = stdIn.nextInt(); 44 45 recur3(x); 46 } 47}

###試したこと

nstk[0] 3 nstk[1] 2 nstk[2] 1
sstk[0] 0 sstk[1] 0 sstk[2] 0

n = nstk[2] = 1
sw = sstk[2] + 1 = 0 + 1 = 1
ptr-- =2 - 1 = 1
sstk[0] 0 sstk[1] 0 sstk[2] 0
n = nstk[1] = 2
sw = sstk[1] + 1 = 1??
###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

メソッドで渡された引数nをメソッド内で書き換えているという恐ろしいソースコードですが。
IDE(eclipse)を使ってデバック実行でブレイクポイントを起きながらステップ実行して変数の値を折ってみると理解しやすいかと。

以下はデバックプリントを追加したソースコードです、ご参考まで。

Java

1import java.util.Arrays; 2import java.util.Scanner; 3import java.util.stream.Collectors; 4import java.util.stream.Stream; 5 6public class Recur3 { 7 static void recur3(int n) { 8 // new int[100]で宣言する意味はないです。 9 int[] nstk = new int[n]; 10 int[] sstk = new int[n]; 11 int ptr = -1; 12 int sw = 0; 13 14 while (true) { 15 if (n > 0) { 16 ptr++; 17 nstk[ptr] = n; 18 sstk[ptr] = sw; 19 if (sw == 0) 20 n -= 1;// n = n - 1; 21 else if (sw == 1) { 22 n -= 2; 23 sw = 0; 24 } 25 continue; 26 } 27 do { 28 n = nstk[ptr]; 29 sw = sstk[ptr] + 1; 30 System.out.println(Stream.generate(() -> "-").limit(30).collect(Collectors.joining(""))); 31 System.out.println(ptr); 32 System.out.println(Arrays.toString(nstk) + ' ' + Arrays.toString(sstk)); 33 ptr--; 34 if (sw == 2) { 35 System.out.println(n); 36 if (ptr < 0) 37 return; 38 } 39 } while (sw == 2); 40 } 41 } 42 43 public static void main(String[] args) { 44 Scanner stdIn = new Scanner(System.in); 45 System.out.print("整数を入力せよ:"); 46 int x = stdIn.nextInt(); 47 recur3(x); 48 } 49 50}

投稿2017/12/30 04:39

umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gyro16

2017/12/30 07:20

ステップ実行でのデバックのやり方を覚えました。参考になりました。 while文の解釈を先入観で見違えていました。 それにしても仮引数を書き換えるなんて良くないですね。 テキストの解答コードが元なので自作ではありません。 再帰的なものを非再帰的に実現するという非合理な問題ですので、作者のセンスが…ということです
guest

0

再帰呼び出しで知っておくべきことは「引数・ローカル変数は呼出しごとに別々の変数の場所が割り当てられる」という点だと思います。

test

1int factorial(int n) { 2 int[] dummy = new int[] { n }; // 意味がないが例のために宣言した 3 if (n == 0) 4 return 1; 5 else 6 return n * factorial(n - 1); 7} 8 9 10int result = factorial(1); 11 -> factorial(1)の呼び出し 12 引数:n = 1 // 変数#1 13 変数:dummy = [ 1 ] // 変数#2 14 -> factorial(0)の呼び出し 15 引数:n = 0 // 変数#3 16 変数:dummy = [ 0 ] // 変数#4

上のコメントの「変数#数字」は変数の場所を表すと考えてください。
上記でfactorial(1)の呼び出し時のn, dummyの変数の場所は変数#1, #2になりますが、factorial(0)の呼び出し時には別の場所#3, #4に記録されます。引数やローカル変数はどの呼び出し中に参照されたかでどの場所の値がアクセスされるかが決まります。

再帰呼び出しでの変数の値に混乱するという場合はこうした意味について把握しておくと混乱を避けられると思います。

このような回答をした理由は、質問者さんの引っかかっている点が

int[] nstk = new int[100];
int[] sstk = new int[100];

これらの配列が各再帰呼び出しにおいて同一のものが参照されるといった勘違いをされているせいではないかと思ったためです。

もしそういう勘違いをしておられないのなら本回答は参考にならないと思います。その場合はおそらく関数内での変数の推移について何かの勘違いをしておられるのが原因であって、再帰呼び出しかどうかとは関係しない問題のように思います。

投稿2017/12/30 04:30

KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問