Desde mi primera clase de programación en la escuela secundaria, he escuchado que las operaciones con cuerdas son más lentas, es decir, más costosas, que la mítica "operación promedio". ¿Por qué los hace tan lentos? (Esta pregunta se dejó intencionalmente amplia).
computer-science
strings
Estallidos
fuente
fuente
Respuestas:
La "operación promedio" tiene lugar en primitivas. Pero incluso en los idiomas en los que las cadenas se tratan como primitivas, siguen siendo matrices debajo del capó, y hacer cualquier cosa que involucre a toda la cadena lleva tiempo O (N), donde N es la longitud de la cadena.
Por ejemplo, agregar dos números generalmente requiere de 2 a 4 instrucciones ASM. Concatenar ("agregar") dos cadenas requiere una nueva asignación de memoria y copias de una o dos cadenas, involucrando la cadena completa.
Ciertos factores del lenguaje pueden empeorarlo. En C, por ejemplo, una cadena es simplemente un puntero a una matriz de caracteres con terminación nula. Esto significa que no sabe cuánto dura, por lo que no hay forma de optimizar un ciclo de copia de cadenas con operaciones de movimiento rápido; necesita copiar un carácter a la vez para poder probar cada byte para el terminador nulo.
fuente
char*
, no unstrbuf
, y vuelves al punto 1. Solo hay tanto puede hacer cuando un mal diseño se incorpora al lenguaje.buf
puntero está ahí. Nunca quise dar a entender que no está disponible; más bien, que es necesario. Cualquier código que no sepa acerca de su tipo de cadena optimizado pero no estándar, incluidas cosas tan fundamentales como la biblioteca estándar , todavía tiene que recurrir a lo lento, insegurochar*
. Puede llamar a ese FUD si lo desea, pero eso no hace que no sea cierto.Este es un hilo viejo y creo que las otras respuestas son geniales, pero pasan por alto algo, así que aquí están mis (tardíos) 2 centavos.
La complejidad sintética del revestimiento de azúcar oculta
El problema con las cadenas es que son ciudadanos de segunda clase en la mayoría de los idiomas y, de hecho, la mayoría de las veces no son realmente parte de la especificación del lenguaje en sí: son una construcción implementada en la biblioteca con algún recubrimiento de azúcar sintáctico ocasional en la parte superior para que sean menos dolorosos de usar.
La consecuencia directa de esto es que el lenguaje oculta una gran parte de su complejidad fuera de su vista, y usted paga los efectos secundarios furtivos porque se acostumbra a considerarlos como una entidad atómica de bajo nivel, al igual que otros tipos primitivos (como se explica en la respuesta más votada y otros).
Detalles de implementacion
Good Ol 'Array
Uno de los elementos de esta "complejidad" subyacente es que la mayoría de las implementaciones de cadenas recurrirían al uso de una estructura de datos simple con algo de espacio de memoria contiguo para representar la cadena: su buena matriz.
Esto tiene sentido, ya que desea que el acceso a la cadena en su conjunto sea rápido. Pero eso implica costos potencialmente terribles cuando desea manipular esta cadena. Acceder a un elemento en el medio podría ser rápido si sabe qué índice está buscando , pero buscar un elemento basado en una condición no lo es.
Incluso devolver el tamaño de la cadena puede ser costoso, si su idioma no almacena en caché la longitud de la cadena y necesita ejecutarla para contar caracteres.
Por razones similares, agregar elementos a su cadena resultará costoso ya que lo más probable es que necesite reasignar algo de memoria para que esta operación ocurra.
Por lo tanto, diferentes idiomas adoptan diferentes enfoques para estos problemas. Java, por ejemplo, se tomó la libertad de hacer que sus cadenas sean inmutables por algunas razones válidas (longitud de almacenamiento en caché, seguridad de subprocesos) y sus contrapartes mutables (StringBuffer y StringBuilder) optarán por asignar el tamaño utilizando trozos de mayor tamaño para no tener que asignarlos. cada vez, pero más bien esperamos los mejores escenarios. Generalmente funciona bien, pero el inconveniente es que a veces se paga por los impactos en la memoria.
Soporte Unicode
Además, y de nuevo esto se debe al hecho de que la capa de azúcar sintáctica de su idioma lo oculta para que juegue bien, a menudo no lo considera términos de soporte Unicode (especialmente mientras no lo necesite realmente y golpear esa pared). Y algunos lenguajes, siendo progresistas, no implementan cadenas con matrices subyacentes de primitivas char simples de 8 bits. Se hornearon en UTF-8 o UTF-16 o lo que tiene soporte para usted, y la consecuencia es un consumo de memoria tremendamente mayor, que a menudo no es necesario, y un mayor tiempo de procesamiento para asignar memoria, procesar las cadenas, e implementar toda la lógica que va de la mano con la manipulación de puntos de código.
El resultado de todo esto es que cuando haces algo equivalente en pseudocódigo para:
Puede que no sea, a pesar de todos los mejores esfuerzos que los desarrolladores de lenguaje pusieron para que se comporten como lo haría excepto, un simple como:
Como seguimiento, es posible que desee leer:
fuente
La frase "operación promedio" es probablemente una abreviatura para una sola operación de una máquina teórica de Programa almacenado de acceso aleatorio . Esta es la máquina teórica que se usa habitualmente para analizar el tiempo de ejecución de varios algoritmos.
Las operaciones genéricas normalmente se toman para cargar, sumar, restar, almacenar, ramificar. Quizás también lea, imprima y pare.
Pero la mayoría de las operaciones de cadena requieren varias de estas operaciones fundamentales. Por ejemplo, duplicar una cadena normalmente requiere una operación de copia y, por lo tanto, una serie de operaciones que es proporcional a la longitud de una cadena (es decir, es "lineal"). Encontrar una subcadena dentro de otra cadena también tiene una complejidad lineal.
fuente
Depende completamente de la operación, cómo se representan las cadenas y qué optimizaciones existen. Si las cadenas tienen 4 u 8 bytes de longitud (y están alineadas), no serían necesariamente más lentas; muchas operaciones serían tan rápidas como las primitivas. O bien, si todas las cadenas tienen un hash de 32 o 64 bits, muchas operaciones también serían igual de rápidas (aunque pague el costo de hash por adelantado).
También depende de lo que quieras decir con "lento". La mayoría de los programas procesarán cadenas con mucha rapidez para lo que se necesita. Las comparaciones de cadenas pueden no ser tan rápidas como comparar dos entradas, pero solo el perfil revelará lo que significa "lento" para su programa.
fuente
Déjame responder tu pregunta con una pregunta. ¿Por qué decir una cadena de palabras lleva más tiempo que decir una sola palabra?
fuente