2016-09-13 12 views
2

プログラムの一部は、順序付きリストを検索する際に2つのc-stringが同一であるかどうかを確認する必要があります(例:{"AAA", "AAB", "ABA", "CLL", "CLZ"})。リストがかなり大きくなる可能性があるので、速度のわずかな向上は可読性の低下に値する。あなたがC++に制限されていると仮定します(アセンブリへの切り替えを推奨しないでください)。どのように改善することができますか?C++ if文の順序

typedef char StringC[5]; 
void compare (const StringC stringX, const StringC stringY) 
{ 
    // use a variable so compareResult won't have to be computed twice 
    int compareResult = strcmp(stringX, stringY); 
    if (compareResult < 0) // roughly 50% chance of being true, so check this first 
    { 
     // no match. repeat with a 'lower' value string 
     compare(stringX, getLowerString()); 
    } 
    else if (compareResult > 0) // roughly 49% chance of being true, so check this next 
    { 
     // no match. repeat with a 'higher' value string 
     compare(stringX, getHigherString()); 
    } 
    else // roughly 1% chance of being true, so check this last 
    { 
     // match 
     reportMatch(stringY); 
    } 
} 

あなたはstringXstringYが常に同じ長さであると仮定することができますし、無効なデータ入力を取得することはありません。

コンパイラは、CPUが最初のif文をチェックして偽であればジャンプするようにコードを作成するので、最初の文が真である可能性が最も高い場合に最適ですジャンプがパイプラインに干渉します。私は、比較を行うときに、[n Intel] CPUが減算を行い、減算の結果を保存せずにフラグの状態を調べると聞いています。 strcmpを1回実行し、結果を変数に保存せずに、最初の2つのif文の両方でその結果を確認することはできますか?

+3

私はあなたがC++(現在あなたがC++構文の_touch_とCコードを持っている)に切り替えることをお勧めしたいです。そのコードパスについてマイクロオプティマイゼーション:**生成されたアセンブリの出力を調べる(驚くかもしれません...)**より重要な入力パターン**(いくつの連続した ' 0 '?)よりも多くの共通コードパスより大きい。最終的な注記:C言語で行う場合、**固定長の文字列には 'strcmp'の代わりに' memcmp'を使用することができます** –

+0

* "結果を変数に保存せずにstrcmpを1回実行する方法"なぜ?! 'strcmp'は結果を' int'の形で生成します。変数はすでにその目的のために割り当てられています。 'compareResult'に格納しないと、何も得られません。あなたの現在のコードは、Cスタイルの構文を選択するといいですね。 – iammilind

+0

'compare'はあなたのプログラムのランタイムを改善する間違ったレベルです。あなたはそれが順序付けされたシーケンスだと言いましたので、はるかに良いアプローチは、あなたのシーケンス(私が推測する)上でのライナー検索ではなくバイナリサーチです。あなたはC++を使っているので、適切なコンテナを使用することができます( 'std :: set ')。 –

答えて

3

std::binary_searchは助けることがあります。

bool cstring_less(const char (&lhs)[4], const char (&rhs)[4]) 
{ 
    return std::lexicographical_compare(std::begin(lhs), std::end(lhs), 
             std::begin(rhs), std::end(rhs)); 
} 

int main(int, char**) 
{ 
    const char cstrings[][4] = {"AAA", "AAB", "ABA", "CLL", "CLZ"}; 
    const char lookFor[][4] = {"BBB", "ABA", "CLS"}; 

    for (const auto& s : lookFor) 
    { 
     if (std::binary_search(std::begin(cstrings), std::end(cstrings), 
           s, cstring_less)) 
     { 
      std::cout << s << " Found.\n"; 
     } 
    } 
} 

Demo

+1

...注文リストjarod。線形時間で行うことができますか、または私は質問を誤解していますか?私たちは重複を探していますか、候補者を探していますか? –

+0

@RichardHodges:対数解( 'cstring_less'呼び出し中)を提案します。これは線形時間よりも優れています。 – Jarod42

+0

私はあなたに異なって質問を読んだと思う。私はそれが重複を確認するよう求めていると思っていた。あなたが正しいと思います。 –

0

ハッシュテーブルを使用すると、比較の速度が大幅に向上すると思います。また、プログラムがマルチスレッド化されている場合は、intelスレッドビルディングブロックライブラリで有用なハッシュテーブルを見つけることができます。たとえば、tbb :: concurrent_unordered_mapはstd :: unordered_mapと同じapiを持っています

私はそれがあなたを助けてくれることを願っています。

+0

私は恐ろしくない、少なくとも劇的にではない。 2つの文字列が既に順序付けられた配列内で同一である場合は、各要素を次の要素と比較するだけでよいので、各要素に対して2つの比較を行います(前の要素を持つ要素と次の要素を持つ要素)。各要素のハッシュを計算し、(ハッシュの)比較の結果が一致する場合は、1つの比較を行う必要があります。結果:文字列を比較する代わりにハッシュを計算し、ハッシュを比較します。ハッシュ計算は文字列比較よりも安価ですが、アルゴリズムは大幅に改善されません*。 –

+0

もちろん、ハッシュテーブルを使用する場合は、複数のエントリを持つハッシュリストを検索するだけです(ただし、ハッシュ配列を直線的に検索する必要があります)ハッシュコリジョン、これは、同じ値にハッシュする*異なるエントリ)です。したがって、これは、各配列エントリに関連付けられたハッシュ値を使用して予想される改善ではありません。 –

0

を使用すると、お互いにすべての文字列を比較しようとする場合は、O(N*(N-1))問題で取得します。リストが大きくなる可能性があると主張しているように(qsortアルゴリズムはO(N*log(N))です)の各要素をリストの次の要素と比較すると、合計がO(N*log(N))の合計複雑度を与えるO(N)が追加されます。 がすでにに注文されているので、各要素を次の要素と比較するだけで、それをトラバースすることができます(O(N)ということになります)。 CやC++で有効な例は、以下の:

for(i = 0; i < N-1; i++) /* one comparison less than the number of elements */ 
    if (strcmp(array[i], array[i+1]) == 0) 
     break; 
if (i < N-1) { /* this is a premature exit from the loop, so we found a match */ 
    /* found a match, array[i] equals array[i+1] */ 
} else { /* we exhausted al comparisons and got out normally from the loop */ 
    /* no match found */ 
} 
+0

質問には[C++]というタグが付いているので、['std :: adjacent_find'](http://www.cplusplus.com/reference/algorithm/adjacent_find/)を使うだけでよいでしょう。 –