2016-09-13 6 views
2

Ein Teil eines Programms muss prüfen, ob zwei C-Strings identisch sind, während der Suche durch eine geordnete Liste (z. B. {"AAA", "AAB", "ABA", "CLL", "CLZ"}). Es ist möglich, dass die Liste ziemlich groß wird, so dass kleine Verbesserungen der Geschwindigkeit die Lesbarkeit beeinträchtigen. Angenommen, Sie sind auf C++ beschränkt (schlagen Sie nicht vor, zur Baugruppe zu wechseln). Wie kann das verbessert werden?C++ if Anweisung Reihenfolge

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); 
    } 
} 

können Sie davon ausgehen, dass stringX und stringY sind immer gleich lang, und Sie werden keine ungültige Dateneingabe erhalten.

Von was ich verstehe, wird ein Compiler den Code so machen, dass die CPU die erste if-Anweisung überprüft und springt, wenn sie falsch ist, also wäre es am besten, wenn diese erste Aussage am wahrscheinlichsten wahr ist Sprünge stören die Pipeline. Ich habe auch gehört, dass bei einem Vergleich eine [n Intel] CPU eine Subtraktion durchführt und den Status von Flags betrachtet, ohne das Ergebnis der Subtraktion zu speichern. Wäre es möglich, die strcmp einmal auszuführen, ohne das Ergebnis in einer Variablen zu speichern, aber dieses Ergebnis während der beiden ersten if-Anweisungen noch überprüfen zu können?

+3

Ich würde vorschlagen, Sie zu C wechseln ++ (derzeit C-Code mit einem _touch_ von C++ Syntax). Über diesen Code Pfad Microoptimization: nicht zu raten versuchen, ** generierte Assembly ** Ausgabe überprüfen (Sie können überrascht sein ...) Auch häufiger als nicht ist ** wichtiger Eingabemuster ** (wie viele aufeinanderfolgende '< 0?) Als der gängigste Codepfad. Schlussbemerkung: Wenn Sie es in C machen, möchten Sie vielleicht 'memcmp' anstelle von' strcmp' für Strings ** fester Länge verwenden ** –

+0

* "Möglichkeit, die strcmp einmal auszuführen, ohne das Ergebnis in einer Variablen zu speichern," * Warum?! 'strcmp' erzeugt sowieso ein Ergebnis in Form von 'int'. Eine Variable ist bereits für den Zweck zugewiesen. Sie werden nichts gewinnen, wenn Sie nicht in 'compareResult' speichern. Ihr aktueller Code scheint gut zu sein, sollten Sie C-Stil-Syntax wählen. – iammilind

+0

'vergleichen' ist die falsche Ebene, auf der die Laufzeit Ihres Programms verbessert werden kann. Du hast erwähnt, dass es sich um eine geordnete Sequenz handelt, also wäre es viel besser, wenn du deine Sequenz (was ich denke) nicht übersegeln, sondern eine binäre Suche machen willst. Da Sie C++ verwenden, könnten Sie einen geeigneten Container verwenden (sagen Sie: 'std :: set '), der für solche algorithmischen Verbesserungen sorgt. –

Antwort

3

std::binary_search kann helfen:

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

... geordnete Liste jarod. Kann in linearer Zeit gemacht werden, oder verstehe ich die Frage nicht? suchen wir nach Duplikaten oder finden einen Kandidaten? –

+0

@RichardHodges: Ich schlage eine Logarithmuslösung vor (in 'cstring_less' Aufrufen), die besser ist als lineare Zeit. – Jarod42

+0

Ich denke ich lese die Frage anders als Sie. Ich dachte, es würde nach Duplikaten suchen. Ich denke, du hast recht. –

0

Ich denke, Hash-Tabellen können die Geschwindigkeit des Vergleichs drastisch verbessern. Wenn Ihr Programm Multithread ist, können Sie auch einige nützliche Hash-Tabellen in der Bibliothek der Intel-Thread-Bausteine ​​finden. Zum Beispiel hat tbb :: concurrent_unordered_map die gleiche api wie std :: unordered_map

Ich hoffe es hilft Ihnen.

+0

Ich fürchte nicht, nicht drastisch zumindest. Wenn zwei Strings in einem bereits geordneten Array identisch sind, müssen Sie nur jedes Element mit dem nächsten vergleichen, so dass Sie nur zwei Vergleiche für jedes Element durchführen (eins mit dem vorherigen Element, ein anderes mit dem nächsten) Um den Hash jedes Elements zu berechnen und im Falle eines Vergleichs (von Hashes) eine Übereinstimmung zu erzielen, müssen Sie einen Vergleich durchführen: Ergebnis: Sie berechnen Hashes und vergleichen Hashes, anstatt Strings zu vergleichen. Hash-Berechnung ist billiger als String-Vergleich, aber der Algorithmus ist nicht * drastisch verbessert *. –

+0

Natürlich, wenn Sie eine Hash-Tabelle verwenden (dies ist nicht der Fall), müssen Sie nur die Hash-Listen mit mehr als einem Eintrag durchsuchen (aber Sie müssen wieder linear das Hash-Array suchen) und dann Einträge vergleichen (zu verwerfen Hash-Kollisionen, dies sind * verschiedene * Einträge, die auf den gleichen Wert Hash-Wert haben. Dies ist also nicht die erwartete Verbesserung, da Hash-Werte für jeden Array-Eintrag verwendet werden. –

0

Wenn Sie versuchen, alle Fäden miteinander vergleichen Sie in einem O(N*(N-1)) Problem zu bekommen. Die beste Sache, wie Sie die Listen groß haben können, ist sie zu sortieren (Algorithmus hat O(N*log(N))) und dann jedes Element mit dem nächsten in der Liste, die eine neue O(N) ergibt insgesamt O(N*log(N)) Gesamtkomplexität . Da Sie die Liste bereits bestellt haben, können Sie es einfach durchlaufen (die Sache O(N) machend) und jedes Element mit dem nächsten vergleichen. Ein Beispiel, gültig in C und C++ folgt:

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

Da die Frage mit [C++] getaggt ist, können Sie einfach ['std :: nebenan_find'] (http://www.cplusplus.com/reference/algorithm/adjacent_find/) verwenden. –