2012-04-11 12 views
6

Mögliche Duplizieren finden:
C++ string::find complexityLeistung std :: strstr vs. std :: string ::

Vor kurzem fand ich heraus, dass die Funktion std::string::find eine Größenordnung langsamer als die Funktion std::strstr - in meiner Umgebung mit GCC 4.7 unter Linux. Der Leistungsunterschied hängt von den Längen der Strings und von der Hardwarearchitektur ab.

Allerdings gibt es einen einfachen Grund für den Unterschied: std::string::find im Grunde ruft std::memcmp in einer Schleife - mit Zeitkomplexität O(m * n). Im Gegensatz dazu ist std::strstr stark für die Hardwarearchitektur optimiert (z. B. mit SSE-Anweisungen) und verwendet einen komplizierteren String-Matching-Algorithmus (anscheinend Knuth-Morris-Pratt).

Ich war auch überrascht, nicht die Zeit Komplexität dieser beiden Funktionen in den Sprachdokumenten zu finden (d. H. Entwürfe N3290 und N1570). Ich habe nur Zeitkomplexitäten für char_traits gefunden. Aber das hilft nicht, denn es gibt keine Funktion für die Teilstringsuche in char_traits.

Ich würde erwarten, dass std::strstr und memmem ähnliche Optimierungen mit fast identischer Leistung enthalten. Und bis vor kurzem nahm ich an, dass std::string::find intern memmem verwendet.

Die Fragen sind: Gibt es einen guten Grund, warum std::string::find nicht std::memmem nicht verwendet? Und ist das bei anderen Implementierungen anders?

Die Frage ist nicht: Was ist die beste Implementierung dieser Funktion? Es ist wirklich schwierig, für C++ zu argumentieren, wenn es langsamer als C ist. Es wäre mir egal, ob beide Implementierungen langsam wären. Es ist der Leistungsunterschied, der wirklich schmerzt.

+0

@FrelichRaabe: Sie haben Recht, es gibt einige Überschneidungen in den beiden Fragen. Aber meine Fragen sind spezifischer, und der andere Artikel beantwortet keine von ihnen. – nosid

+0

@nosid: Ja, tut es. Sehen Sie sich insbesondere die zusätzliche Erklärung in Kommentaren von dietmar kuhl über den durchschnittlichen Fall und den schlechtesten Fall und die Raumkomplexität an, warum dies höchstwahrscheinlich nicht verwendet wird. Diese Argumente ändern sich nicht, wenn Sie 'std :: memmem' iso wiederverwenden und den Algorithmus von Grund auf neu implementieren. – KillianDS

Antwort

2

Zuerst, was ist memmem? Ich kann dies weder im C++ - Standard noch im Posix-Standard finden (der alle Standard-C-Funktionen enthält).

Zweitens hängen alle Messwerte von den tatsächlichen Daten ab. Bei Verwendung von wird zum Beispiel KMP in vielen Fällen eine Pessimierung sein; wahrscheinlich die meisten Fälle, in denen die Elementfunktionen von std::string verwendet werden; Die Zeit zum Einrichten der erforderlichen Tabellen ist oft mehr als die Gesamtzeit des direkten Algorithmus. Dinge wie O(m*n) bedeuten nicht viel, wenn die typische Länge der Zeichenfolge kurz ist.

+0

Ich nehme an, dass "Memmem" Teil von C ist, aber anscheinend nicht. 'memmem' ist' strstr' was 'memcmp' zu' strcmp' ist. Aber Sie wissen das sicher. Trotzdem, wie ich schon ein paar Mal erwähnt habe. Die Frage ist nicht, ob KMP eine gute Wahl ist.Die Frage ist, warum sie völlig unterschiedliche Algorithmen für 'strstr' und' std :: string :: find' verwenden. – nosid

+0

@nosid Vielleicht, weil das erwartete Verwendungsmuster anders ist? Oder weil verschiedene Autoren unterschiedliche Nutzungsmuster bevorzugen? In den meisten Anwendungen, die ich gesehen habe, sind die meisten Strings ziemlich kurz, wobei die längsten Strings vielleicht einer Linie entsprechen. Für solche Saiten wäre die Verwendung von etwas wie KMP wahrscheinlich eine Pessimierung. Wenn die Autoren von 'memmem' dachten, dass der typische Anwendungsfall Blöcke von mehreren KB Speicher oder mehr beinhalten würde, lohnt es sich auf jeden Fall. –

+0

Laut meinen Benchmarks, vom 25.06.2013: für GCC ist string :: find etwas schneller (~ 10%) (x86_64, -march = nativ, lief auf AWS) - für MSVC 2, mal langsamer (x86, SSE2 , auf dem Desktop von AMD). (vollständige Optimierungen) – Etherealone

Verwandte Themen