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

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

新規登録して質問してみよう
ただいま回答率
85.46%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

433閲覧

再帰関数の流れを教えていただきたいです。

cunwe

総合スコア65

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/05/23 08:34

こちらの問題の解答コード(以下に載せました)で再帰関数の基本を学びたいのですが再帰関数を解説してるブログを見ても理解できません。。
######質問内容
.if (x==1) return 1;というのがベースケース、return f(x/2)*2+1;が再帰ステップと呼ばれるものだと思うのですが再帰関数の解説ブログには異口同音に「再帰ステップでの再帰呼び出しが最終的にベースケースに到達する」と書いてあります。今回例えばxに19という数字を入れたときにどういう流れを経てx==1に辿り着くのか詳細に教えてくださると嬉しいです。自分はxに19を与える→x!=1だからf(x/2)*2+1に放り込まれる→f(9)*2+1を返す(どこに?)ぐらいで理解が止まっています。よろしくお願い致します。

#include <bits/stdc++.h> using namespace std; long long f(long long x) { if (x==1) return 1; return f(x/2)*2+1; } int main(){ long long h; cin >> h; cout << f(h) << endl; return 0; }

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

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

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

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

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

guest

回答3

0

xに19を与える→x!=1だからf(x/2)*2+1に放り込まれる→f(9)*2+1を返す

同じステップを続けるだけです。f(9)からはf(4)を呼び出すコードになり、f(4)f(2)を呼び出し、最終的にはf(2)が返り値の決まっているf(1)を呼び出します。

C++では、(staticや関数外の変数を読み書きする場合は別として)「再帰呼び出し」と言っても全く特別なことはなく、単にたまたま同じ名前の関数を呼び出していると考えて問題ありません。「f(19)からf(9)を呼び出した」からと言って両者が干渉することはなく、f(9)は単体で呼び出したときと同じ動作をします。

投稿2020/05/23 08:43

maisumakun

総合スコア145208

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

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

cunwe

2020/05/24 08:37

ベストアンサーはひとりしか選べないので代わりに+高評価1させていただきました。ご回答ありがとうございました。
guest

0

c++

1#include <bits/stdc++.h> 2using namespace std; 3 4long long f(long long x) { 5 if (x==1) return 1; 6 long long wk = f(x/2); 7 return wk*2+1; 8} 9 10int main(){ 11 long long h; 12 cin >> h; 13 cout << f(h) << endl; 14 return 0; 15}

説明上wkに変数を入れるとしてh=19のときの説明だから
cout << f(19) << endl;f(19)で関数呼び出される・・・mとおく

f(19)関数内で long long wk = f(x/2);wkに値代入するためにf(19/2)が呼び出される(f(9))・・・Aとおく

f(9)関数内で long long wk = f(x/2);wkに値代入するためにf(9/2)が呼び出される(f(4))・・・Bとおく

f(4)関数内で long long wk = f(x/2);wkに値代入するためにf(4/2)が呼び出される(f(2))・・・Cとおく

f(2)関数内で long long wk = f(x/2);wkに値代入するためにf(2/2)が呼び出される(f(1))・・・Dとおく

(f(1))なので if (x==1) return 1;が呼び出されて1を返す(Dのwkに1が入る)

Dのwk代入後の処理でreturn wk*2+1;なので1*2+1を返す(Cのwkに3が入る)

Cのwk代入後の処理でreturn wk*2+1;なので3*2+1を返す(Bのwkに7が入る)

Bのwk代入後の処理でreturn wk*2+1;なので7*2+1を返す(Aのwkに15が入る)

Aのwk代入後の処理でreturn wk*2+1;なので15*2+1を返す(mのf(19)が31となる)

mのf(19)は31が帰ってきたので31を出す

投稿2020/05/23 08:49

編集2020/05/23 08:51
rururu3

総合スコア5545

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

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

cunwe

2020/05/24 08:36

ベストアンサーはひとりしか選べないので代わりに+高評価1させていただきました。ご回答ありがとうございました。
guest

0

ベストアンサー

1 main() から f(19) を呼び出した時、x = 19 なので

c++

1return f(x/2)*2+1;

の際にまず f(19/2) つまり f(9) が呼ばれます。

2 f(9) が呼ばれると該当の return 文で f(9/2) つまり f(4) が呼ばれます。

3 f(4) が呼ばれると該当の return 文で f(4/2) つまり f(2) が呼ばれます。

4 f(2) が呼ばれると該当の return 文で f(2/1) つまり f(1) が呼ばれます。

5 f(1) が呼ばれると x = 1 なので if (x==1) return 1; で f(1) を呼んだ f(2) に 1 が return されます。

6 f(2) では、f(x/2)*2+11*2+1 つまり 3 になるので f(2) を呼んだ f(4) に 3 が return されます。

7 f(4) では、f(x/2)*2+13*2+1 つまり 7 になるので f(4) を呼んだ f(9) に 7 が返されます。

8 f(9) では、f(x/2)*2+17*2+1 つまり 15 になるので f(9) を呼んだ f(19) に 15 が返されます。

9 f(19) では、f(x/2)*2+115*2+1 つまり 31 になるので f(9) を呼んだ main() に 31 が返されます。

投稿2020/05/23 09:01

Yasumichi

総合スコア1773

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

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

cunwe

2020/05/24 02:49

他の方のブログを読んだときには気づかなかったのですが、ということは再帰関数内でおこなっているのは、言葉が適切ではないかもしれませんが「行って帰って」という感じなのでしょうか?また、今回のこの再帰関数の計算量というのはどれぐらいなのでしょうか?よろしくお願いいたします。
Yasumichi

2020/05/24 04:10

「行って帰って」に近いですかね。 見た目上の計算回数は、そんなに増えていかないですが、再帰の場合、関数呼び出しのオーバーヘッド等(スタックへの変数の退避等)も考えないといけません。 関数の呼び出し回数だけに着目すると 入力h → 呼び出し回数 10 →  4 100 → 7 1000 → 10 という感じです。
cunwe

2020/05/24 08:34

だいぶ少ないですね。while文で実装したらTLE(Time Limit Exceeded)したので再帰関数の有用性を実感できました。ありがとうございました!
Yasumichi

2020/05/24 08:40

呼び出し回数は少ないですが、ほかにも考慮に入れないと正確な計算量はでないみたいです。 [初心者向け] プログラムの計算量を求める方法 - Qiita https://qiita.com/cotrpepe/items/1f4c38cc9d3e3a5f5e9c とかだと実際の計算方法は省かれてますね。 > 参考までに、コードに再帰が含まれている場合は、以下の方法で計算量を求めることになります。 > > 漸化式を解く方法 > 公式を利用する方法 あと、対象が再帰的なデータ構造であるかどうかが再帰を使う場合の一つの指針になると思います。
cunwe

2020/05/24 09:06

計算量が気になったらこのページに戻ってきて見たいと思います。対象が再帰的なデータ構造であるかどうかを見極めらるのにはもう少し時間がかかってしまいそうですが頑張りたいと思います。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問