22

以下のようなswitchステートメントがあるとしましょう

switch(alphabet) {

    case "f":
        //do something
        break;

    case "c":
        //do something
        break;

    case "a":
        //do something
        break;

    case "e":
        //do something
        break;

}

Alphabetここで、 e を持つ頻度が最も高く、次にそれぞれ a、c、f が続くことがわかっているとします。そのため、ステートメントの順序を再構築caseして、次のようにしました。

switch(alphabet) {

    case "e":
        //do something
        break;

    case "a":
        //do something
        break;

    case "c":
        //do something
        break;

    case "f":
        //do something
        break;
}

2 番目のswitchステートメントは最初のステートメントよりも高速switchですか? はいの場合、私のプログラムでこのswitchステートメントを何度も呼び出す必要がある場合、それは大幅な改善になりますか? または、そうでない場合、周波数の知識を使用してパフォーマンスを向上させるにはどうすればよいですか?

4

4 に答える 4

23

気にするほどではありません。それは確かに予測できるものではありません。

文字列ケース ラベルを使用すると、コンパイラは実際には、文字列をジャンプ テーブルのインデックスにマップする内部ハッシュ テーブルを使用します。したがって、操作は実際には O(1) であり、ラベルの数とは関係ありません。

整数ラベルの場合、生成される実際のコードは、ラベルの数と、数値が連続しているかどうか (または「ほぼ」連続しているかどうか) に依存すると思います。それらが連続している場合 (1、2、3、4、...)、ジャンプ テーブルに変換されます。それらが多数ある場合は、Hashtable+jump テーブル (文字列の場合と同様) が使用されます。ラベルが数個しかなく、それらがすぐにジャンプ テーブルに変換されるテーブルでない場合、一連の if..then..else ステートメントに変換されます。

ただし、一般的には、コンパイラが「より高速な」コードを生成できるようにするためではなく、読めるようにコードを作成する必要があります。

(上記の説明は、C# コンパイラが内部でどのように機能するかの実装の詳細であることに注意してください。常にそのように機能することに依存するべきではありません。 )。

于 2010-05-12T03:46:18.283 に答える
3

これは、コンパイラがswitchステートメントを実装する方法によって異なります。

まず、順序を任意に並べ替えることはできません。Cのような言語(C、C ++、C#、Javaなど)で1つのケースブロックがあり、そのケースブロックがブレークで終了しない場合、ブレークがないということは、ケースを再配置できないことを意味します。コンパイラは、次のケースへのフォールスルーを実装する必要があります。この特別な状況を無視すれば、残りのケースを並べ替えることができます。

ケースの数が少ない場合、コンパイラーは一連の比較によってケーステストを実装する場合があります。ケースの数が少ない場合は、ケースからバランスの取れた二分木を構築できます。ケースの数が多い場合、ほとんどのコンパイラは、スイッチ値が密なセットからのものである場合、スイッチ値にインデックス付きブランチを実装します。ケース値のセットの一部が密であり、一部が密でない場合、コンパイラは、バイナリツリーを使用してケースをグループに分割し、どの密セットを選択するか、および密セット内のインデックス付きジャンプを使用できます。(実際、コンパイラーは技術的には適切なケースに制御を渡すものなら何でも実行できますが、ほとんどの場合、上記のいずれかです)。

コンパイラがスイッチをどのように実装するかによって、順序が重要になる場合とそうでない場合があります。ほとんどの優れたコンパイラにとって、それはそれほど重要ではありません。

于 2010-05-12T03:54:07.203 に答える
2

これらは、比較的小さな値のセットに対して同じパフォーマンスを示します。前に C プログラムのアセンブリ コードをチェックしようとしましたが、コンパイラは、switch ステートメントにあるすべての値からジャンプ テーブルを作成します。

しかし、大文字と小文字の値が多すぎる場合、それらが に退化するのは安全な賭けであるif else ifため、大文字と小文字の「E」を上に置くと確実に速度が上がります。

C#でも適用できます。C# は、隣接する値のみではありますが、小さなセットを持つ switch ステートメントのジャンプ テーブルも生成します。つまり、O(1) です。最初の値が一致しなくても、複数のテストはありません。

于 2010-05-12T03:45:30.377 に答える
-3

スイッチケースのやり方は、すべてのケースを上から下にループして一致を見つけることだと思います。一致する場合は、そこで停止します。

したがって、頻度のケースを優先するように変更を加えた場合、答えは「はい」です。何らかの形でパフォーマンスを向上させることができます。しかし、それはあまり役に立たないと私は信じています。

于 2010-05-12T03:42:04.423 に答える