再帰的なプログラムを非再帰的なものへと書き換えたいです。
途中まで挑戦していたのですが、うまくいきません。
関数recurAが元の関数で、この表記方法と同じ表記にするように関数recurBを書き換えたいです。
情けないながら未だ初心者知識しかなく、理解力に乏しい状況です。
そこで、大変申し訳ないのですがわかりやすい解説も頂ければ幸です。
何卒よろしくお願い申し上げます。
環境はLinuxです。
以下未完成のソースになります。
//再帰に対する理解を深めるための真に再帰的な関数3
#include <stdio.h>
/*真に再帰的な関数recurA*/
void recurA(int n)
{
if(n>0){
if(n%2 == 0) recurA(n/2);
else recurA(n-1);
printf("%d",n);
recurA(n-2);
}
}
/*再帰を除去した関数recurB*/
void recurB(int n){//0
int D,K;
D = K = 0;
D = K = n;
/*------第1判定------*/
Top:
if(n>1){
if(n%2==0){
n = n/2;
}
else {
n = n-1;
}
printf("%d",n);
goto Top;
}
/*------与えられたnを表示させる------*/
if(D==K)printf("%d",D);
/*------第2判定------*/
D = D-2;
n = D;
if(D>0){
printf("%d",D);
goto Top;
}
}
int main(void)
{
int x;
printf("整数を入力せよ : ");
scanf("%d",&x);
recurA(x);
printf("\n");
recurB(x);
printf("\n");
return 0;
}
【至急】再帰的なプログラムを非再帰的なものへ
【至急】再帰的なプログラムを非再帰的なものへ
最後に編集したユーザー みなみ on 2016年6月27日(月) 23:58 [ 編集 1 回目 ]
-
- 記事: 21
- 登録日時: 9年前
- 住所: 近畿
Re: 再帰的なプログラムを非再帰的なものへ
goto文の飛び先を示すラベルです。
コードの中に
goto Top;
っていう記載がありますよね。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 再帰的なプログラムを非再帰的なものへ
仰るとおり、Topはこのソースコードに置けるラベルとなっております。
goto Topに差し掛かったら自動でTop:の箇所まで戻り、そこから再び実行されます。
はいの整数10の場合上の関数Aが正しい表記なので、下のBを上と同じ表記にさせたいのです。
1241251231101241281231612412
5421108421632142121
個人的な見解としては、n-2まで実行した後のnがn-1の判定を通り抜けてしまっているものと思っています。
それとnのソートがうまくいっていないため、正しいnが求められていても、正しいならびかたになりません...。
goto Topに差し掛かったら自動でTop:の箇所まで戻り、そこから再び実行されます。
はいの整数10の場合上の関数Aが正しい表記なので、下のBを上と同じ表記にさせたいのです。
1241251231101241281231612412
5421108421632142121
個人的な見解としては、n-2まで実行した後のnがn-1の判定を通り抜けてしまっているものと思っています。
それとnのソートがうまくいっていないため、正しいnが求められていても、正しいならびかたになりません...。
Re: 再帰的なプログラムを非再帰的なものへ
nのソートって何でしょうか。みなみ さんが書きました: それとnのソートがうまくいっていないため、正しいnが求められていても、正しいならびかたになりません...。
そもそも、再帰呼び出しを使った想定解を出力するコードにおいて
nをソートしているわけではなさそうに見えますので、
非再帰の場合においても同様なのではないですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
-
- 記事: 21
- 登録日時: 9年前
- 住所: 近畿
Re: 【至急】再帰的なプログラムを非再帰的なものへ
みなみ さん
再帰処理では、仮引数の値を使用して何かしらの処理をさせるのですが、
この『仮引数の値』を使う順番が、『FILO (入れ後出し)』または、『FIFO(先入れ先出し)』で使用していきます。
つまり、データ構造『スタック』『キュー』に『仮引数の値』を『push』または『enq』し、
それらの情報を使いたいときに、『pop』または『deq』すればよいことになります。
具体的には、
の『仮引数の値を使用して何かしらの処理をさせる』部分の
以前に呼び出しに使用した引数(== 次の関数での仮引数)が、『FILO (入れ後出し)』、
以後に呼び出しに使用した引数(== 次の関数での仮引数)が、『FIFO(先入れ先出し)』となります。
ここまで、偉そうに書いていますが自分は『スタック』までしか学習していません。
なので、『仮引数の値を使用して何かしらの処理をさせる』部分の、以前の記述しかでませんでした。
あと、出力形式が少し違いますがご了承ください。
みなみ さん の質問には答えきれていませんが、参考程度にどうぞ
再帰処理では、仮引数の値を使用して何かしらの処理をさせるのですが、
この『仮引数の値』を使う順番が、『FILO (入れ後出し)』または、『FIFO(先入れ先出し)』で使用していきます。
つまり、データ構造『スタック』『キュー』に『仮引数の値』を『push』または『enq』し、
それらの情報を使いたいときに、『pop』または『deq』すればよいことになります。
具体的には、
void recurA(int n)
{
if(n > 0){
if(n % 2 == 0) recurA(n/2);
else recurA(n - 1);
printf("%d", n);
recurA(n - 2);
}
}
以後に呼び出しに使用した引数(== 次の関数での仮引数)が、『FIFO(先入れ先出し)』となります。
ここまで、偉そうに書いていますが自分は『スタック』までしか学習していません。
なので、『仮引数の値を使用して何かしらの処理をさせる』部分の、以前の記述しかでませんでした。
あと、出力形式が少し違いますがご了承ください。
► スポイラーを表示
Re: 【至急】再帰的なプログラムを非再帰的なものへ
スタックを使えばよいのでは?
#include <stdio.h>
int s[10000], p;
void recurB(int n)
{
while (1) {
while (n > 0) {
s[p++] = n;
n = n & 1 ? n - 1 : n / 2;
}
if (p == 0) return;
n = s[--p];
printf(" %d", n);
n -= 2;
}
}
int main(void)
{
int x;
while (printf("整数を入力せよ : "), scanf("%d", &x) == 1) {
recurB(x);
printf("\n");
}
return 0;
}
Re: 【至急】再帰的なプログラムを非再帰的なものへ
元のプログラムに合わせて、n & 1 を (n % 2 == 0) にしました。
#include <stdio.h>
void recurB(int n)
{
static int s[10000], p;
while (1) {
while (n > 0) {
s[p++] = n;
n = (n % 2 == 0) ? n / 2 : n - 1;
}
if (p == 0) return;
n = s[--p];
printf(" %d", n);
n -= 2;
}
}
int main(void)
{
int x;
while (printf("整数を入力せよ : "), scanf("%d", &x) == 1) {
recurB(x);
printf("\n");
}
return 0;
}