1

したがって、いくつかの for ループを使用して可変高さの数値ピラミッドを作成する関数を既に作成しており、完全に機能します。

私が話している種類のピラミッドの例を次に示します。

ユーザーが 4 を入力

      1 

    1 2 1

  1 2 3 2 1 

1 2 3 4 3 2 1 

したがって、左側に空白を埋め込む必要があります。

私の問題は、再帰のみ、ループなしで動作させることができないことです。再帰に関しては、どこから始めるべきかさえ思いつきません。基本ケースと、その基本ケースにアプローチする方法が必要であることはわかっています。

複数の再帰関数を書くべきですか、それとも 1 つだけでそれを行う方法はありますか? (メインに加えて、つまり。)

これが私がこれまでに持っているものです(それほど多くはありません):

void givepyramid(int lines);  //lines = Number of lines in pyramid (4 in example above)
{
     if lines == 1;
        cout << (//all the spaces needed)<<1;
     else
         cout << (I'm not too sure on how to go about this here.)
}

どんなアドバイスでも大歓迎です!ありがとう。

4

7 に答える 7

2

ループを使用せずにきれいな三角形を描く簡単なソリューションを次に示します。

#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. 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 を再度印刷することと同じです。など、最小値が最大値と同じになるまで、その数値を出力するだけです (それが基本ケースです)。

  2. 何度も何かを印刷し、そのたびにインデントを減らしながら新しい行に印刷します。何か (たとえば、手紙) を何度も出力できる関数が必要です。最後の行はまったくインデントされていません。単純なケースでは、1 行だけを印刷します。この場合、インデントはまったくありません。2 行を印刷することは、たとえば 2 のインデントを付けて最初に 1 行を印刷し、次にその行を再度印刷することと同じです。3 行を印刷するということは、最初に 2 のインデントで 2 行を印刷することを意味し (つまり、1 行を 4 のインデントで印刷することを意味します!)、次に 3 行目をインデントなしで印刷します。

    私たちのコードはたまたまランダムな文字を出力しませんでした。代わりに、drawTriangle関数はインデントを正しく取得 (および改行を出力)printRowNumbersし、実際の数字を出力させます。

ご覧のとおり、私はひどく分析的なアプローチを使用しませんでした (ループを再帰に書き換えることができるため、ループを記述してから、いくつかの規則に従って再帰に機械的に変換することができます)。代わりに、「これを 2 回行うことは 1 回だけ行うこととどのように異なるのか、3 回行うことは 2 回行うこととどのように異なるのか」などのいくつかの実験を手作業で行い、パターンを見つけました。

于 2013-10-10T20:31:51.097 に答える
0

ループのない単純で再帰的な関数:

void printTree(int maxLevel, int currLevel = 0, int currPos = 1)
{
    if(currLevel>maxLevel)
        return;
    if(currPos<(maxLevel-currLevel))
    {
        cout<<'\t';
        printTree(maxLevel, currLevel, ++currPos);
    }
    else if(currPos<(maxLevel-currLevel + currLevel*2)-1)
    {
        cout<<((maxLevel - currPos)<=0?(currPos - maxLevel)+2:(maxLevel - currPos))<<'\t';
        printTree(maxLevel, currLevel, ++currPos);
    }
    else
    {
        cout<<endl;
        printTree(maxLevel, ++currLevel, 0);
    }
}

あなたの例では、関数を次のように呼び出しますprintTree(4)

于 2013-10-10T19:36:47.863 に答える
0

あなたは交換することができます

for (int i = 0; i != N; ++i) {
    body(i, localVars);
}

void body_rec(int N, int i, LocalVars& localVars)
{
    if (i == N) return;
    body(i, localvars);
    body_rec(N, i + 1, localVars)
}
于 2013-10-10T19:43:37.730 に答える
0

10 を超える数に対して機能し、ループなしで完全に機能します。

PS:C++11

#include <iostream>
#include <vector>
#include <string>


void gen_numbers(int len, int number, std::string &ans) {

    if (len > 1) {
        ans.append(std::to_string(number));
        ans.push_back(' ');
        gen_numbers(len - 1, number + 1, ans);
        ans.push_back(' ');
        ans.append(std::to_string(number));
    }
    if (len == 1)
        ans.append(std::to_string(number));

}

void print_spaces(int number) {
    std::cout << " ";
    if (number)
        print_spaces(number - 1);
}

void draw (int line, int depth) {
    if (line > 1) {
        draw(line - 1, depth);
    }

    print_spaces(2 * (depth - line));
    std::string ans;
    gen_numbers(line, 1, ans);
    std::cout << ans;
    print_spaces(depth - line);
    std::cout << std::endl;
}



int main() {
    draw(12, 12);
    return 0;
}
于 2013-10-10T19:14:04.317 に答える