2012-04-11 39 views
6

Duplicar posible:
C++ string::find complexityRendimiento std :: strstr vs std :: string :: encontrar

Recientemente he descubierto, que la función std::string::find es un orden de magnitud más lento que la función std::strstr - en mi entorno con GCC 4.7 en Linux. La diferencia de rendimiento depende de la longitud de las cadenas y de la arquitectura del hardware.

Sin embargo, hay una razón simple para la diferencia: std::string::find básicamente llama a std::memcmp en un bucle - con complejidad de tiempo O(m * n). Por el contrario, std::strstr está altamente optimizado para la arquitectura de hardware (por ejemplo, con instrucciones SSE) y utiliza un algoritmo de coincidencia de cadenas más sofisticado (aparentemente Knuth-Morris-Pratt).

También me sorprendió no encontrar las complejidades de tiempo de estas dos funciones en los documentos de idioma (es decir, borradores N3290 y N1570). Solo he encontrado complejidades de tiempo para char_traits. Pero eso no ayuda, porque no hay función para la búsqueda de subcadenas en char_traits.

Supongo que std::strstr y memmem contienen optimizaciones similares con un rendimiento casi idéntico. Y hasta hace poco, asumí que std::string::find usa internamente el memmem.

Las preguntas son: ¿Hay alguna buena razón, ¿por qué std::string::find no utiliza std::memmem? ¿Y esto es diferente con otra implementación?

La pregunta no es: ¿Cuál es la mejor implementación de esta función? Es realmente difícil argumentar a favor de C++, si es más lento que C. No me importaría si ambas implementaciones fueran lentas. Es la diferencia de rendimiento lo que realmente duele.

+0

@FrerichRaabe: Tiene razón, hay una superposición en las dos preguntas. Pero mis preguntas son más específicas, y el otro artículo no responde ninguna de ellas. – nosid

+0

@nosid: sí, lo hace. Mire en particular la explicación adicional en los comentarios de dietmar kuhl sobre el caso promedio frente al peor de los casos y la complejidad del espacio, por qué es muy probable que esto no se use. Esos argumentos no cambian si reutiliza 'std :: memmem' iso implementando el algoritmo desde cero. – KillianDS

Respuesta

2

Primero, ¿qué es memmem? No puedo encontrar esto en el estándar C++ ni en el estándar Posix (que contiene todas las funciones C estándar).

En segundo lugar, cualquier valor de medición dependerá de los datos reales. Usar KMP, por ejemplo, será una pesimista en muchos casos; probablemente la mayoría de los casos donde se usan las funciones miembro de std::string; el tiempo para configurar las tablas necesarias a menudo será más que el tiempo total del algoritmo directo. Cosas como O(m*n) no significan mucho cuando la longitud típica de la cuerda es corta.

+0

Asumí que 'memmem' es parte de C, pero aparentemente no lo es. 'memmem' es' strstr' que 'memcmp' es' strcmp'. Sin embargo, estoy seguro de que lo sabes. Sin embargo, como ya he mencionado algunas veces. La pregunta no es si KMP es una buena opción.La pregunta es por qué están utilizando algoritmos completamente diferentes para 'strstr' y' std :: string :: find'. – nosid

+0

@nosid ¿Quizás porque el patrón de uso esperado es diferente? ¿O porque diferentes autores han privilegiado diferentes patrones de uso? En la mayoría de las aplicaciones que he visto, la mayoría de las cadenas son bastante cortas, y las cadenas más largas corresponden quizás a una línea. Para tales cadenas, usar algo como KMP probablemente sería una pesimización. Si los autores de 'memmem' pensaban que el caso típico de uso involucraría bloques de varios KB de memoria o más, por otro lado, definitivamente vale la pena. –

+0

Según mis puntos de referencia, a partir del 25.06.2013: para GCC, string :: find es ligeramente más rápido (~ 10%) (x86_64, -march = nativo, ejecutó en AWS) - para MSVC 2, tiempos más lentos (x86, SSE2 , en el escritorio AMD). (optimizaciones completas) – Etherealone

Cuestiones relacionadas