5

私はいくつかの統計を計算するこのメソッドを持っています:

public void calculateAverage(int hour){

    if (hour != 20) {
        int data =0; 
        int times = 0;
        for (CallQueue cq : queues) {
            data += cq.getCallsByTime().get(hour);
            times++;
        }       
        averageData.add((double)data/times);
        calculateAverage(hour + 1);
    }
    
}

今、私は再帰的なメソッドを作成したことを非常に誇りに思っていますが、これはループで解決できた可能性があることを知っています。

私の質問は、この種の問題を再帰的に解決するのが良いのか、それともループで解決するのが良いのかということです。

4

5 に答える 5

7

一般的な再帰

一般に、関数が再帰するたびにスタックを変数のコピーで変更する必要があるため、再帰はより高価になります。

特定の実行後に再帰手順が正しい状態に戻ることができるように、一連のアドレスと状態を保存する必要があります。

可能であれば、反復がより良いでしょう。再帰、反復がうまくいかない場合、またはより複雑なコードになる場合


コードのメンテナンス

メンテナンスの観点からは、反復コードのデバッグは、特定の再帰について考えるよりも、特定の反復での状態を比較的簡単に理解できるため、再帰手順よりもはるかに簡単です。


あなたのコード

プロシージャはそれ自体を呼び出しますが、各実行は前の実行の結果とは何の関係もありません。各実行が独立していることは、通常、再帰が必要ない可能性があるという最大のメリットです。

私の意見でcalculateAverage(hour + 1);は、コードを読んでいる人にもわかりやすいので、関数の外に移動する必要があります。各呼び出しが独立していること。

于 2012-11-12T15:26:52.210 に答える
2

Java、C、およびPythonでは、再帰は新しいスタックフレームの割り当てを必要とするため、反復(一般的に)と比較してかなりコストがかかります。一部のCコンパイラでは、コンパイラフラグを使用してこのオーバーヘッドを排除できます。これにより、特定のタイプの再帰(実際には特定のタイプの末尾呼び出し)が関数呼び出しではなくジャンプに変換されます。(ソース

于 2012-11-12T15:29:03.847 に答える
1

この特定の問題については、実行時間の違いはあまりありません。私は個人的にはむしろ反復を使用したいと思います。よりシンプルで理解しやすいと思いますが、それぞれに独自のものだと思います。

現在、いくつかの再帰関数 (たとえば、再帰的なフィボナッチ数など) は、単純に指数関数的に増加する可能性があるため、反復によって実行する必要があります。

一般に、問題を実際に理解しやすくする場合を除き、再帰は使用しません。

于 2012-11-12T15:27:11.070 に答える
1

周囲の状況を調査する必要があります。大きな再帰スタックの場合、オーバーフローが発生する可能性があります。ループの場合は +1 です。

どちらがより速く実行されるかはわかりませんが、JIT やその他のことを考慮して、比較的簡単に測定できます。

コード メンテナンスの側面: ほとんどの人にとって、再帰よりもループを理解して修正する方がはるかに簡単です。通常、開発者の時間は、わずかなパフォーマンスの違いよりも重要です。

于 2012-11-12T15:27:36.467 に答える
1

文脈によります。たとえば、Composite(SWT で) オブジェクトのツリーがあり、それらをトラバースしたい場合、最も簡単な方法は次のように再帰を使用することです。

    private boolean checkControlParent(Composite comp) {
        boolean ret = false;
        if (comp != null) {
            if (this.equals(comp)) {
                ret = true;
            } else {
                ret = checkControlParent(comp.getParent());
            }
        }
        return ret;
    }

それ以外の場合、パフォーマンスが重要な場合は、ほとんどの場合、再帰呼び出しは関数/メソッド呼び出しのオーバーヘッドのために単純なループよりも遅くなることに注意してください。

したがって、主なことは、再帰が自然な解決策であり、先に進んで再帰を使用する危険を冒さないオブジェクトを反復処理する必要がある場合ですStackOverflowError。それ以外の場合は、ループを使用したほうがよいでしょう。

もう 1 つ: 再帰的メソッドは、読み取り、理解、およびデバッグが困難になる傾向があります。

于 2012-11-12T15:28:12.793 に答える