¿Por qué comparar cadenas 0 (n), pero comparar números 0 (1)?

8

Entiendo que para comparar dos cadenas para la igualdad, el intérprete tiene que recorrer ambas cadenas y comparar cada carácter.

Eso haría que la complejidad del tiempo 0(n), donde nes la longitud de la cadena más corta.

Sin embargo, comparar dos números para igualdad es 0(1).

¿Porqué es eso? ¿No tendría que interpretar el intérprete cada número para verificar la igualdad?

Nick Akey
fuente
1
¿Qué hay para iterar en un número? Un número es solo el valor: 2por ejemplo, no lo es 3. Eso es. Del mismo modo 123no lo es 124. Una cadena es una colección de caracteres "abc"diferente "abd"pero tiene que verificar cada carácter.
VLAZ
2
Las computadoras tienen operaciones intrínsecas que comparan valores de números enteros rápidamente.
Puntiagudo
55
Si está trabajando en un idioma como Erlang con enteros de precisión infinita, las comparaciones numéricas son realmente O (n)
puntiaguda el
1
Además, en lugar de "a través de cada número", probablemente se refiera a "a través de cada dígito"
Pointy
1
@Pointy: Eso sería O (log (n)), porque la longitud de n número es proporcional a log (n).
Nyos

Respuestas:

10

Los números en las computadoras generalmente se manejan en unidades de tamaño fijo. Un intpuede ser de 32 o 64 bits en cualquier combinación de idioma y / o compilador / plataforma, pero nunca será de longitud variable.

Por lo tanto, tiene un número fijo de bits para comparar al comparar números. Es muy fácil construir un circuito de hardware que compare tantos bits a la vez (es decir, como "una acción").

Las cadenas, por otro lado, tienen longitudes inherentemente variables, por lo que solo decir "cadena" no le dice cuántos bits tendrá que comparar.

Sin embargo, hay excepciones, ya que hay números de longitud variable, generalmente llamados algo así BigIntegero BigDecimalque se comportarán de manera muy similar a la Stringcomparación, ya que podría terminar siendo O (n) para comparar dos BigDecimalvalores de igualdad (donde n es la longitud de la BigDecimals , ninguno de sus valores numéricos).

Joachim Sauer
fuente
¿La presencia de la etiqueta javascript hace alguna diferencia en esta respuesta? En javascript tienen los operadores ===y ==, donde el ==operador permite hacer algo como lo 1 == '1'que se evaluará como verdadero, pero los documentos son muy vagos en cuanto a qué se convierten cada uno de los operandos antes de que se haga la comparación. Entonces, en este caso, si se convierten en una cadena, la comparación puede no ser una comparación de enteros, sino una comparación de cadenas
smac89
@ smac89: JavaScript utiliza un solo tipo numérico que es un número de coma flotante de tamaño fijo, por lo que no hay diferencia en la comparación. Sí, antes de la comparación, es posible que deba hacer algunas conversiones que pueden o no ser factibles en O (n), pero la OMI no es realmente parte de la comparación.
Joachim Sauer
3
@ smac89 " pero los documentos son muy vagos en cuanto a a qué se convierten cada uno de los operandos antes de que se haga la comparación ", los documentos son MUY explícitos en cómo se debe hacer la comparación entre los diferentes tipos.
VLAZ
@VLAZ gracias por el enlace. Por lo tanto, parece que la cadena se convierte en número, que todavía es O(n)y ese es mi punto con mencionar esto especialmente cuando se trata de JavaScript.
smac89
@JoachimSauer JavaScript uses a single numberic typeeso no es correcto. BigInt ahora es un tipo incorporado en JavaScript
phuclv
4

Por lo general, los programas representan números como estructuras de datos de tamaño fijo (valores binarios, por lo que puede ver sus tamaños descritos en bits). Al ser de tamaño fijo, las comparaciones tomarían una cantidad constante de tiempo y serían O (1), que es uno de los beneficios de dicha representación. Una desventaja sería un límite en el rango de valores que se pueden representar.

Una representación alternativa que levanta esta restricción, permitiendo un rango de números arbitrariamente grande, por lo tanto, ya no sería de tamaño fijo, y ya no sería O (1) para comparar.

Scott Hunter
fuente
0

Cuerda

Las comparaciones de cadenas suelen ser una exploración lineal de los caracteres, que devuelve falso en el primer índice donde los caracteres no coinciden.

La complejidad del tiempo es O (N) y el tiempo real que se necesita depende de cuántos caracteres deben escanearse antes de que surjan diferencias estadísticamente. No hay una respuesta simple, pero la respuesta es obvia ;-)

Números

Si dos enteros son iguales, es imposible saberlo sin comparar todos sus bits. Entonces, en caso de igualdad, el tiempo necesario es proporcional al número de bits (que es proporcional al log (abs (N)) si N es uno de los comparables).

Si de hecho no son iguales, hay muchos casos, todos relevantes para la implementación interna. Las entradas largas se almacenan como un vector de "dígitos" en una base de potencia de 2. Si los vectores no tienen las mismas longitudes, entonces las entradas no son iguales, y eso lleva un tiempo constante.

Pero si tienen la misma longitud, entonces los "dígitos" deben compararse hasta encontrar el primer par (si lo hay) que no coinciden. Eso lleva un tiempo proporcional al número de dígitos que deben compararse.

Mazhar Khan
fuente
Los dígitos no se comparan. Los bits se comparan. Y los bits se comparan como un grupo atómico. Ninguna computadora compara el bit 1, luego el bit 2, luego el bit 3, luego el bit 4. Dependiendo de la instrucción particular utilizada y las capacidades del procesador, comparan 8 bits, o 16 bits, o 32 bits, o 64 bits, etc. , como una sola operación. No hay comparación de nivel de dígitos o el equivalente, está en los límites de byte / palabra.
Ghedipunk
0

En general, solo usamos la notación big-O cuando n puede elevarse a valores obscenamente grandes, porque la notación big-O describe cómo crece el tiempo de ejecución a medida que crece la entrada. Por ejemplo, al ordenar una lista, la mayoría de los mejores algoritmos se ordenan O(n log n), lo que significa, y solo significa, que cuando la lista es lo suficientemente larga, el tiempo que lleva ordenarla es proporcional n log n. Cuando la lista no es lo suficientemente larga, otros factores (por ejemplo, en cualquier momento que su algoritmo pueda tomar para asignar espacio adicional), se vuelven significativos e incluso pueden tomar el tiempo de ejecución.

Con las cadenas de JavaScript, de nhecho puede ser arbitrariamente grande *, por lo que decimos que la comparación lleva O(n)tiempo. Pero con los números de JavaScript (que son números de coma flotante de precisión doble IEEE 754 ), ntiene un límite máximo de 64-1 para un bit de signo, 11 para un exponente y 53 para dígitos significativos **. Debido a esto, sabemos exactamente cuánto tiempo tomará una comparación de números, y los mejores sistemas que tenemos para comparar números de ese tamaño exacto funcionan más o menos independientemente de cuántos de esos 64 dígitos cada número realmente tiene, por lo tanto, se considera comparar estos números en JavaScript O(1).


* Técnicamente, hay un límite superior porque la memoria RAM puede agotarse. Sin embargo, el idioma no especifica un tamaño máximo para las cadenas, y elO(n) parte de la comparación de cadenas domina el tiempo de ejecución mucho antes de que eso suceda.

** Por cierto, esto significa que los números en JavaScript no pueden aumentar infinitamente. Más allá de cierto punto, comienzan a tirar dígitos más pequeños (por ejemplo, los números superiores a 2 ^ 53 solo pueden ser pares, y los números superiores a 2 ^ 54 solo pueden ser divisibles por 4), y cuando el número se hace lo suficientemente grande, se redondea hasta el infinito. Por el contrario, si divide un número una y otra vez para hacerlo infinitamente pequeño, eventualmente se redondeará a cero.

TheHansinator
fuente