4

for開始条件と終了条件の両方がわかっているループを作成する場合、どちらの方法が優れていますか? サイズ 5 の配列要素を追加するためにループを繰り返す必要があるとしましょう。この場合、実行時間に関する限り、次のうちどれがより効率的でしょうか? どちらがより良いパフォーマンスを発揮しますか?

for (i = 0; i < 5; i++)
{
    /* logic */
}

また

for (i = 4; i >= 0; i--)
{
    /* logic */
}

i = 5 - 1;である書き込みの難しさ以外i = 4;に、他に考慮すべき点はありますか?

4

7 に答える 7

9

通常は、マイクロ最適化やその他の要因を気にせずに、コードをできるだけ明確かつ論理的にすることに専念することをお勧めします。あなたの場合、ほとんどのプログラマーは配列をその順序でトラバースすることに慣れているため、最初のものがより良い選択です。

どちらのバージョンも (正しく実装されていれば) 同じ結果になり、実行時間もまったく同じになります。

EDIT:@Zaneはコメントで、ゼロに逆方向にループする方が少し前に高速であると述べました。その理由は、変数をゼロと比較する方が高速だったからです。当時のコンピューターははるかに遅かったため、このような最適化が推奨されました。そんな日々は本当に終わった…

于 2012-11-08T10:48:50.280 に答える
4

コードに何か問題があります。最初のループは問題ありませんが、2 番目の while は決して実行されません: 0 回実行されます。そのはず

for(i=4;i>=0;i--){}

また、どちらが良いかと問われれば、どちらが使いやすいかはあなた次第です。私にとっては、最初の方が快適に感じます。

于 2012-11-08T10:49:57.307 に答える
2

ほとんどの場合、問題にはなりませんが、明らかでない副作用が干渉する状況がいくつかあります。ループを考えてみましょう:

for(int i = 0; i < strlen(str); i++) {/* do stuff on i-th elem */}. ここでは、反復ごとに strlen(str) が再評価されます (コンパイラーによって最適化されていない限り)。プログラマーはおそらくこれを考慮していませんでした。ループを次のように置き換える価値があるかもしれません:

for(int i = strlen(str); i > 0; i--) {/* do stuff on i-th elem */}. ここで、文字列の長さは一度だけ評価されます。

もちろん、最初のループでは、追加の変数を使用して文字列の長さを保持することで問題を回避することもできますが、これは単なる不要なノイズであり、プログラム ロジックとは関係ありません。

于 2012-11-08T10:57:37.293 に答える
2

最も明白な答えは次のとおりです。必要なセマンティクスを持っているのはどれですか? オブジェクトを異なる順序で訪問します。

原則として、他に考慮事項がない場合、人々は昇順を期待します。これは、オブジェクトにアクセスするときに使用する必要があるものです。C++ では、これに反復子を使用する方がはるかに慣用的です。通常のイテレータは昇順でアクセスし、逆のイテレータは降順でアクセスします。明示的に降順が必要ない場合は、通常の反復子を使用する必要があります。これは人々が期待することであり、リバース イテレータを使用する場合、読者が最初に尋ねるのはその理由です。また、測定はしていませんが、通常のイテレータが逆イテレータよりも高速であったとしても驚かないでしょう。Java では、反復子も慣用的であり、逆反復子はありません。

訪問時に降順が必要な場合は、while ループを使用します (逆反復子がない場合は、それが自動的に実行されます)。私は次のようなものを見つけます:

int index = numberOfElements;
while ( index != 0 ) {
    -- index;
    //  ...
}

どの代替手段よりもはるかに読みやすく (そして正しく理解するのが簡単です)。

オブジェクトにアクセスするのではなく、カウントするだけの場合は、降順の方が自然に思えます。制御変数には残りの回数が含まれます。また、カウントがインデックスとして使用されることはありませんので、インデックスとして 1 つオフになっても問題はなく、従来のfor.

for ( int count = numberOfTimes; count != 0; -- count ) {
    //  ...
}

しかし、それはスタイルの問題です。これについても、多くの上昇ループを見てきました。

于 2012-11-08T11:16:31.100 に答える
0

インクリメンタル for ループまたはデクリメント for ループは、カウンター変数の使用方法や見栄えの良さに基づいて選択されます。

  • 昇順で配列にアクセスしている場合、デクリメント for ループが使用されます

    for (i = 0; i < 5; i++) { arr[i]; }

  • 配列またはリストに降順でアクセスしている場合は、インクリメンタル for ループが使用されます。

    for (i = 5; i > 0 ; i--) { arr[i-1]; }

  • アクセスされる値に対してカウンタ番号が意味を持たない場合は、コードの可読性が考慮されます。また、インクリメンタル for ループの方が見栄えがします。

于 2012-11-08T11:17:39.237 に答える
0

ほとんどのプログラマーは、最初の方法 (i++) を使用すると、コードをより迅速に理解できると思います。配列を逆に処理する必要がない限り、最初の方法に固執します。パフォーマンスに関しては、どちらのソリューションもほとんどまたはまったくメリットがないと思います。

また、 for..each (拡張 for ) 構文の使用を検討することもできます。これは非常に整頓されています。

    int[] x = {1,2,3,4,5};

    for(int y: x){
        System.out.println(y);
    }
于 2012-11-08T10:48:01.413 に答える
0

i++ を使用したループの方が理解しやすいと思います。また、逆方向に進むと、プロセッサ キャッシュが最適に使用されない可能性がありますが、通常、コンパイラ/仮想マシンはそれよりもスマートです。

于 2012-11-08T10:50:54.210 に答える