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

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

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

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

Q&A

解決済

3回答

1008閲覧

再帰的なメソッドをスタックを使って非再帰的に書くには?

gyro16

総合スコア89

Java

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

0グッド

1クリップ

投稿2017/12/30 08:04

編集2017/12/30 09:14

###前提・実現したいこと
IntStackはInt型のスタック、先入れ後出しのStackです。

static void recur3(int n){
if(n > 0){
recur3(n-1);
recur3(n-2);
System.out.println(n);
}
これをIntStackをつかって

static void recur3(int n){
IntStack s = new IntStack(100);
if(n > 0){
s.push(n);
n = n - 2;
}
continue;
if(s.isEmpty() != true){
n = s.pop();
System.out.println(n);
}
}

これだと
static void recur3(int n){
if(n > 0){
recur3(n-2);
System.out.println(n);
}
}
しかなりません

IntStackをつかって書くにはどうすれば良いでしょうか?
recur(n-1)まで含めて書くにはどうすれば良いでしょうか?

スタック 入り口 1, 2, 1, 3 底

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

static void recur3(int n){ if(n > 0){ recur3(n-1); recur3(n-2); System.out.println(n); }

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

java

1static void recur3(int n){ 2 IntStack s = new IntStack(100); 3 if(n > 0){ 4 s.push(n); 5 n = n - 2; 6 } 7 continue; 8 if(s.isEmpty() != true){ 9 n = s.pop(); 10 System.out.println(n); 11 } 12} 13 14static void recur3(int n){ 15 int nn = n; 16 IntStack s = new IntStack(100); 17 if(n > 0){ 18 s.push(n); 19 n = n - 2; 20 } 21 continue; 22 if(nn > 0) 23 nn = nn - 1; 24 s.push(nn); 25 } 26 continue; 27 if(s.isEmpty() != true){ 28 n = s.pop(); 29 System.out.println(n); 30 } 31} 32

###試したこと
recur3(1)→ recur3(0) recur3(-1) Sys.out.1 → Sys.out.1
recur3(2)→ recur3(1) recur3(0) Sys.out.2 → Sys.out.1 Sys.out.2
recur3(3)→ recur3(2) recur(1) Sys.out.3 → Sys.out.1 Sys.out.2 Sys.out.1 Sys.out.3

スタック 入り口 1, 2, 1, 3 底

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

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

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

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

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

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

anndonut

2017/12/30 11:38

ちなみに「該当のソースコード」にはrecur3メソッドが2つ書いてありますね。2つのコードを試したけど両方ダメだったという意味でしょうか?
guest

回答3

0

ベストアンサー

Deque<Integer>を使った書き方です。「Forthの力を信じよ!」ってやつです。

java

1import java.util.Deque; 2import java.util.ArrayDeque; 3 4public class Main { 5 public static final int RECURSION = 0; 6 public static final int PRINT = 1; 7 8 public static void recur3(int n) { 9 // Javaのドキュメントによると、Stackクラスの代わりに 10 // Dequeインターフェースを使用することが推奨されています。 11 Deque<Integer> stack = new ArrayDeque<Integer>(); 12 stack.push(n); 13 stack.push(RECURSION); 14 while (!stack.isEmpty()) { 15 if (stack.pop() == RECURSION) { 16 int num = stack.pop(); 17 if (num > 0) { 18 stack.push(num); 19 stack.push(PRINT); 20 stack.push(num - 2); 21 stack.push(RECURSION); 22 stack.push(num - 1); 23 stack.push(RECURSION); 24 } 25 } else { // stack.pop() == PRINT 26 System.out.println(stack.pop()); 27 } 28 } 29 } 30 31 public static void main(String[] args) { 32 recur3(3); 33 } 34}

投稿2017/12/30 12:23

編集2017/12/31 01:58
anndonut

総合スコア667

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

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

anndonut

2017/12/31 03:06

このコードを解説するために、デバッグ用の出力を追加したものを用意しました。 https://gist.github.com/haruo-wakakusa/db9ce844370f4359effa49f992fb810e まず、recur3(1)について出力してみましょう。 [0, 1] [0, 0, 0, -1, 1, 1] [0, -1, 1, 1] [1, 1] 1 [] こうなります。Dequeでpush, popを行うと、データの末尾ではなく先頭にデータが追加・削除されるようですね。これを、Forth風(ただしForthとは逆の書き方)に書くと、こうなります。 R 1 R 0 R -1 P 1 R -1 P 1 P 1 1が出力 スタックが空になり、終了。 つまり、Rがrecur3メソッドで、PがSystem.out.printlnメソッドに対応する命令です。Forthでは命令と引数を同じ型で表現しても正しく動作するので、R=0, P=1としています。 recur3(1)の開始時には、R 1という命令を置いています。これは分かりやすいですね。 次の行では、R 1の引数である1が0より大きいので、R 0 R -1に展開されます。 その次の行では、R 0が先頭に来ていますが、Rの引数が0なので、0より大きくなく、そのまま消費されます。 その次の行では、R -1が先頭に来ていますが、Rの引数が-1なので、0より大きくなく、そのまま消費されます。 その次の行では、P 1が先頭に来ていますが、Pはその引数を表示するので、1を表示します。 この時点で、スタックが空になったので、プログラムを終了します。 recur3(2)以降についても同様のことが言えます。分からなければさらに解説させて頂きます。
gyro16

2017/12/31 03:36

分かりました。分かりやすいです。 Dequeでもpushやpopできるんですね。
guest

0

java

1import java.util.Scanner; 2public class En5_5b{ 3 static void recur3(int n) throws IntStack.OverflowIntStackException, IntStack.EmptyIntStackException{ 4 int num = n; 5 IntStack s = new IntStack(100); 6 while(n > 0){ 7 try{ 8 s.push(n); 9 }catch(IntStack.OverflowIntStackException e){ 10 System.out.println("スタックが満杯です。"); 11 } 12 n -= 2; 13 } 14 while(num-1 > 0){ 15 try{ 16 s.push(num-1); 17 }catch(IntStack.OverflowIntStackException e){ 18 System.out.println("スタックが満杯です。"); 19 } 20 num--; 21 } 22 while(s.isEmpty() != true){ 23 try{ 24 n = s.pop(); 25 }catch(IntStack.EmptyIntStackException e){ 26 System.out.println("スタックが空です。"); 27 } 28 System.out.println(n); 29 } 30 } 31 public static void main(String[] args){ 32 Scanner stdIn = new Scanner(System.in); 33 System.out.println("整数を入力せよ:"); 34 int n = stdIn.nextInt(); 35 recur3(n); 36 } 37}

投稿2017/12/30 10:46

gyro16

総合スコア89

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

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

anndonut

2017/12/30 12:00

gyro16さんのコードはn=4のときに1 2 3 2 4と出力しませんか?貪欲法で解きに行ってこけてるように思われたので。
guest

0

分かりづらいけどこんな感じです。もっと分かりやすい回答があったらそっちに習ったほうがいいかもしれませんね。IntStackは使ってないです。Stackクラスを使ってます。

java

1import java.util.Stack; 2 3public class Main { 4 public class Recur3 { 5 private int num = 0; 6 private Stack<Recur3> s = null; 7 8 public Recur3(int n, Stack<Recur3> stack) { 9 num = n; 10 s = stack; 11 } 12 13 public void run() { 14 if (num > 0) { 15 s.push(new Printer(num, s)); 16 s.push(new Recur3(num-2, s)); 17 s.push(new Recur3(num-1, s)); 18 } 19 } 20 } 21 22 public class Printer extends Recur3 { 23 private int num = 0; 24 25 public Printer(int n, Stack<Recur3> stack) { 26 super(n, stack); 27 num = n; 28 } 29 30 public void run() { 31 System.out.println(num); 32 } 33 } 34 35 private Recur3 create(int n, Stack<Recur3> stack) { 36 return new Recur3(n, stack); 37 } 38 39 public static void main(String[] args) { 40 Stack<Recur3> s = new Stack<Recur3>(); 41 s.push((new Main()).create(4, s)); 42 while (!s.empty()) { 43 s.pop().run(); 44 } 45 } 46}

投稿2017/12/30 09:09

編集2017/12/30 11:36
anndonut

総合スコア667

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

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

gyro16

2017/12/30 09:42

ロジック違いませんか?結果違うと思いますよ ただ並列で並べただけでは再帰的な結果とは違いますよ
anndonut

2017/12/30 10:21

Javaの内部クラスが分かって、しかもForthという言語が分かるなら僕のやってることが分かると思う。
gyro16

2017/12/30 10:51

recur3(3)は1 2 1 3ですから、答えが違いますよ。 recur3(4)でもrecur3(3) recur3(2) Sys.out.4 ですから1 2 1 3 1 2 4ですから結果が違いますよ。
anndonut

2017/12/30 11:34

gyro16さん、ご指摘ありがとうございます。ケアレスミスでした。コード直しておきます。
gyro16

2017/12/30 12:17

箱型に箱型を押し込む。それを再帰的に繰り返すスタックですか。
anndonut

2017/12/30 12:50

IntStackクラスは本の中に登場するものだと思いますが、一般的にはjava.util.Stackクラスを使います。ただ、Stackクラスは総称型(ジェネリクス)で、型引数を必要とします。型引数にはintなどのプリミティブ型を指定することはできません。ただ、int型のラッパーであるInteger型を型引数にとることができ、IntStackクラスと同様の使い方ができます。Forthはoperatorとargumentを逆順で並べる言語ですが、逆順で並べるとスタックの構造と相性がいいのでそうします。詳しくは私のもう一つのコードをご参照ください。
swordone

2017/12/30 14:40

Stackは古いので、Dequeで宣言してLinkedListやArrayDequeを使うべき。
anndonut

2017/12/30 23:43

Stackは古いかもしれないけど、Stackを使わないとForthを実装してる感が出ないんじゃない?Dequeを使う場合は、「これはスタックとして使っています」と、コメントを添えるべき。あと、できることなら代替コードを示して、具体的に、速度的に優れているとか、サイズが大きくなるとオーダー的に優れているとか示してあげると親切だと思います。
swordone

2017/12/31 01:35

速度などの問題ではなく、Stackのドキュメントに記載されている事です。 https://docs.oracle.com/javase/jp/8/docs/api/java/util/Stack.html > より完全で一貫性のある一連のLIFOスタック・オペレーションが、Dequeインタフェースとその実装によって提供されています。このクラスよりもそれらを優先的に使用するようにしてください。
anndonut

2017/12/31 01:45 編集

それは判断が厳しいねー。そもそも質問者さんがDequeというものを理解しているかですよね。Stackが使用不推奨になっていなければ今回の場合はStackで実装でいいと思いますけどね。
anndonut

2017/12/31 01:55

ちょい直しで済んだので、もう一つの回答の方でStack<Integer>をDeque<Integer>に直しておきました。swordoneさん、ご指摘ありがとうございます。
gyro16

2017/12/31 02:04

if(num > 0)で並列でpushしていてなぜ0以下がpushされないのですか? num-2,num-1ではチェックしていませんよね?
swordone

2017/12/31 02:18

そもそも質問者はIntStackというおそらくオリジナルのクラスを使っているのにあなたが勝手にStackを使いだしたんだから、 「質問者がDequeを理解しているか」というのはお門違い。
gyro16

2017/12/31 02:24

numが減っていく機序はどうなってるのですか? デバッグでブレークポイントで見たのですがよく分かりません。
anndonut

2017/12/31 02:40

swordoneさん、おっしゃる通りです。というかIntStackというクラスを使っているからこそ他の回答者さんはなかなか手を出すことができずに、私とgyro16さんのほうで忖度して回答しているということなんだと思います。
anndonut

2017/12/31 02:42

gyro16さん、このコードは分かりづらいので、もう一つのコードの方で解説させて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問