¿Hay alguna situación en la que la estructura de datos de la cuerda es más eficiente que un constructor de cadena

StackOverflow https://stackoverflow.com/questions/1863440

¿Fue útil?

Solución

La documentación para el SGI C ++ aplicación entra en algunos detalles en la gran O comportamientos versos los factores constantes que es instructivo.

Su documentación asume cadenas muy largas están involucrados , los ejemplos postularon para la charla de referencia acerca de 10 cuerdas MB . Muy serán escritos pocos programas que se ocupan de este tipo de cosas y, para muchas clases de problemas con tales requisitos reelaborando que sean basan corriente en lugar de requerir la cadena completa que esté disponible cuando sea posible, dará lugar a significativamente superior resultados. Como tales cuerdas son para la manipulación no transmisión de secuencias de caracteres de múltiples megabytes cuando son capaces de tratar adecuadamente la cuerda como secciones (ellos mismos cuerdas) en lugar de sólo una secuencia de caracteres.

significativas Pros:

  • La concatenación / Inserción convertido en operaciones en tiempo casi constantes
  • Ciertas operaciones pueden reutilizar las secciones de cuerda anteriores para permitir el intercambio en la memoria.
    • Tenga en cuenta que las cadenas .Net, a diferencia de las cadenas de Java no comparten la memoria intermedia de caracteres en subseries - una opción con ventajas y desventajas en términos de consumo de memoria. Cuerdas tienden a evitar este tipo de problema.
  • Cuerdas facilitan la carga diferida de subcadenas hasta que se requiera
    • Tenga en cuenta que esto es difícil de hacerlo bien, muy fácil de hacer inútil debido al excesivo afán de acceso y requiere el consumo de código para tratarla como una cuerda, no como una secuencia de caracteres.

Significativo Contras:

  • acceso de lectura aleatoria se convierte en O (log n)
  • Los factores constantes sobre el acceso de lectura secuencial parecen estar entre 5 y 10
  • uso eficiente de la API requiere tratándolo como una cuerda, no sólo dejando caer en una cuerda como una aplicación de respaldo en la API 'normal' cadena.

Esto conduce a unos pocos usos 'obvias' (el primero mencionado explícitamente por SGI).

  • Editar tampones en archivos de gran tamaño que permite un fácil deshacer / rehacer
    • Tenga en cuenta que, en algún momento puede que tenga que escribir los cambios en el disco, con la participación de streaming a través de toda la cadena, por lo que esto sólo es útil si la mayoría de las modificaciones se residen principalmente en la memoria en lugar de requerir frecuente persistencia (digamos a través de una función de copia de seguridad automática )
  • Manipulación de segmentos de ADN donde se produce la manipulación significativa, pero muy poco de salida que realmente sucede
  • hilos múltiples algoritmos que mutar subsecciones locales de cadena. En teoría tales casos pueden ser parcelados OFF para hilos y núcleos separados sin necesidad de tomar copias locales de las subsecciones y luego recombinar ellos, el ahorro de memoria considerable, así como evitar una operación de combinación de serie costoso al final.

Hay casos en que el comportamiento específico de dominio en la cadena puede acoplarse con aumentos relativamente sencillas para la puesta en práctica de la cuerda para permitir:

  • Sólo lectura cadenas con un número significativo de subcadenas comunes son susceptibles de internar sencilla para los ahorros significativos de memoria.
  • Cuerdas con estructuras dispersas, o repetición local significativa son susceptibles de ejecutar la codificación de longitud mientras que todavía permite niveles razonables de acceso aleatorio.
  • Cuando los límites sub cadena son en sí mismas 'nodos' donde la información puede ser almacenada, aunque tales estructuras son bastante posible una mejor hecho como un Radix Trie si rara vez se modifican, pero a menudo se leen.

Como se puede ver en los ejemplos mencionados, todos caen bien en la categoría de 'nicho'. Además, varios bien puede haber alternativas superiores si estás dispuesto / capaz de reescribir el algoritmo como una operación de procesamiento de flujo en su lugar.

Otros consejos

La respuesta corta a esta pregunta es sí, y que requiere poca explicación. Por supuesto que hay situaciones en las que la estructura de datos cuerda es más eficiente que un constructor de cadena. que funcionan de manera diferente, por lo que son más adecuados para diferentes propósitos.

(Desde una perspectiva de C #)

La estructura de datos cuerda como un árbol binario es mejor en ciertas situaciones. Cuando usted está buscando en los valores de cadena extremadamente grandes (más de 100 MB de pensar xml que viene de SQL), la estructura de datos cuerda podía seguir todo el proceso de la montón de objetos grandes, donde el objeto de cadena pega cuando pasa a 85000 bytes.

Si usted está buscando en las cadenas de caracteres 5-1000, probablemente no mejora el rendimiento suficiente para merecer la pena. Este es otro caso de una estructura de datos que está diseñado para el 5% de las personas que tienen una situación extrema.

El Programming Contest 10a ICFP se basó , básicamente, en las personas que utilizan la estructura de datos de la cuerda para la resolución eficiente. Ese fue el gran truco para conseguir una máquina virtual que corría en un tiempo razonable.

La cuerda es excelente si hay un montón de prefijo (al parecer, la palabra "anteponiendo" se compone por la gente y no es una palabra adecuada!) Y potencialmente mejor para las inserciones; StringBuilders utilizan memoria continua, por lo que sólo funciona de manera eficiente para anexar.

Por lo tanto, StringBuilder es ideal para la construcción de cadenas añadiendo fragmentos - un caso de uso muy normal. A medida que los desarrolladores tienen que hacer esto mucho, StringBuilders son una tecnología muy corriente principal.

Cuerdas son grandes para tampones de edición, por ejemplo la estructura de datos detrás de, digamos, un TextArea empresa resistencia. Por lo tanto (una relajación de las cuerdas, por ejemplo, una lista enlazada de líneas en lugar de un árbol binario) es muy común en el mundo controles de IU, pero eso no es a menudo expuesto a los desarrolladores y usuarios de esos controles.

Es necesario realmente grandes cantidades de datos y batir para hacer la cuerda de amortización - procesadores son muy buenos en las operaciones de ruta, y si usted tiene la memoria RAM entonces simplemente realloc para prefijar funciona aceptablemente para casos de uso normales. Esa competencia se menciona en la parte superior fue la única vez que he visto que necesitaba.

editores de texto más avanzados representan el cuerpo del texto como "una especie de cuerda" (aunque en la implementación, las hojas no son por lo general personajes individuales, pero el texto corre), principalmente para mejorar las inserciones de los frecuentes y borra en textos grandes.

Generalmente, StringBuilder está optimizado para anexar y trata de minimizar el número total de reasignaciones sin overallocating a mucho. La garantía típica es (log2 N asignaciones, y menos de 2,5 veces la memoria). Normalmente, la cadena se construye de una vez y se puede entonces utilizar durante bastante tiempo sin ser modificado.

cuerda está optimizado para las inserciones y eliminaciones frecuentes, y trata de minimizar cantidad de datos copiados (por un mayor número de asignaciones). En una aplicación lineal de búfer, cada inserción y el borrado se convierte en O (N), y por lo general tienen que representar inserciones de un solo carácter.

Javascript máquinas virtuales suelen utilizar cuerdas para las cadenas.

Maxime Chevalier-Boisvert, desarrollador del Higgs Javascript VM, dice :

  

En JavaScript, puede utilizar matrices de cadenas y, finalmente,   Array.prototype.join para hacer la concatenación de cadenas razonablemente rápido,   O (n), pero la forma "natural" de JS programadores tienden a construir cadenas es   acaba de añadir usando el operador + = para construir incrementalmente ellos. JS   las cadenas son inmutables, por lo que si esto no se ha optimizado internamente,   Anexión de incremental es O (n2). Creo que es probable que las cuerdas eran   implementado en los motores de JS específicamente debido a la SunSpider   los puntos de referencia que hacen Anexión de cadena. ejecutores del motor JS utilizan   cuerdas para obtener una ventaja sobre los demás, haciendo algo que era   previamente lento más rápido. Si no fuera por esos puntos de referencia, creo   que llora de la comunidad sobre Anexión de cadena mal desempeño   pueden haber sido recibido con "usar Array.prototype.join, maniquí!".

también .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top