ループを使用せずにきれいな三角形を描く簡単なソリューションを次に示します。
#include <iostream>
void printRowNumbers( unsigned int n, unsigned int max )
{
if ( n < max ) {
std::cout << n << ' ';
printRowNumbers( n + 1, max );
}
std::cout << n << ' ';
}
void drawTriangle( unsigned int n, unsigned int indent = 0 )
{
if ( n > 1 ) {
drawTriangle( n - 1, indent + 2 );
}
std::cout << std::string( indent, ' ' );
printRowNumbers( 1, n );
std::cout << "\n";
}
主なアイデアは、ループを使用して通常取り組む2つの問題があるということです:
1 2 3 2 1
またはのように (特定のインデントなしで) 数字の行を出力します1 2 3 4 5 4 3 2 1
。重要なアイデアは、数値を最大値まで出力して元に戻すだけでなく、実際には、ある開始値 (常に1
ここにあるようです) から最大値まで数値を出力してから最初に戻すということです。価値。
洞察としては、1 から 5 までの「数のミラー」を印刷して元に戻すことは、1 を印刷してから 2 から 5 までのミラーを印刷し、次に 1 を再度印刷することと同じことです。そして、2 から 5 へのミラーリングを印刷することは、2 を印刷してから 3 から 5 へのミラーリングを行い、次に 2 を再度印刷することと同じです。など、最小値が最大値と同じになるまで、その数値を出力するだけです (それが基本ケースです)。
何度も何かを印刷し、そのたびにインデントを減らしながら新しい行に印刷します。何か (たとえば、手紙) を何度も出力できる関数が必要です。最後の行はまったくインデントされていません。単純なケースでは、1 行だけを印刷します。この場合、インデントはまったくありません。2 行を印刷することは、たとえば 2 のインデントを付けて最初に 1 行を印刷し、次にその行を再度印刷することと同じです。3 行を印刷するということは、最初に 2 のインデントで 2 行を印刷することを意味し (つまり、1 行を 4 のインデントで印刷することを意味します!)、次に 3 行目をインデントなしで印刷します。
私たちのコードはたまたまランダムな文字を出力しませんでした。代わりに、drawTriangle
関数はインデントを正しく取得 (および改行を出力)printRowNumbers
し、実際の数字を出力させます。
ご覧のとおり、私はひどく分析的なアプローチを使用しませんでした (ループを再帰に書き換えることができるため、ループを記述してから、いくつかの規則に従って再帰に機械的に変換することができます)。代わりに、「これを 2 回行うことは 1 回だけ行うこととどのように異なるのか、3 回行うことは 2 回行うこととどのように異なるのか」などのいくつかの実験を手作業で行い、パターンを見つけました。