¿Cómo se sabe qué notación de análisis de complejidad de tiempo utilizar?

91

En la mayoría de las clases de algoritmos introductorios, se introducen anotaciones como (Big O) y , y un estudiante generalmente aprendería a usar una de estas para encontrar la complejidad del tiempo.OΘ

Sin embargo, hay otras notaciones, como , y . ¿Hay escenarios específicos donde una notación sería preferible a otra?oΩω

Jack H
fuente
2
no es tan preferible como sea ​​aplicable ...
vzn

Respuestas:

76

Te refieres a la notación de Landau . No son símbolos diferentes para la misma cosa, pero tienen significados completamente diferentes. Cuál es "preferible" depende completamente de la declaración deseada.

f g f o ( g ) <fO(g) significa que crece como máximo tan rápido como , asintóticamente y hasta un factor constante; piense en ello como un . es la forma más estricta, es decir, .fgfo(g)<

f g ω f Ω ( g ) g O ( f )fΩ(g) tiene el significado simétrico: crece al menos tan rápido como . es su primo más estricto. Puede ver que es equivalente a .fgωfΩ(g)gO(f)

f g f O ( g ) Ω ( g ) f g Θ OfΘ(g) significa que crece casi tan rápido como ; formalmente . (igualdad asintótica) es su forma más fuerte. A menudo nos referimos a cuando usamos .fgfO(g)Ω(g)fgΘO

Observe cómo y sus hermanos son clases de función . Es importante ser muy consciente de esto y sus definiciones precisas, que pueden diferir dependiendo de quién está hablando, al hacer "aritmética" con ellos.O(g)

Al probar cosas, tenga cuidado de trabajar con su definición precisa. Existen muchas definiciones para los símbolos de Landau (todas con la misma intuición básica), algunas de las cuales son equivalentes en algunos conjuntos de funciones pero no en otros.

Lectura sugerida:

Si está interesado en utilizar la notación de Landau de manera rigurosa y sólida, puede interesarle el trabajo reciente de Rutanen et al. [1] Formulan los criterios necesarios y suficientes para la notación asintótica cuando los usamos en algoritmos, muestran que la definición común no cumple con ellos y proporciona una definición (de hecho) viable.


  1. Una definición general de la notación O para el análisis de algoritmos por K. Rutanen et al. (2015)
Rafael
fuente
55
Solo quiero señalar que aunque actúa como y actúa como , hay diferencias; que no es difícil de encontrar funciones y tal que y . Ω g f f O ( g ) f Ω ( g )OΩgffO(g)fΩ(g)
Zach Langley
1
+1 por la mención de las clases de función. Cosas como y aparecen en todas partes en documentos y libros, lo que puede ser confuso para las personas que enfrentan estas anotaciones por primera vez. Ω ( 2 n )o(1)Ω(2n)
Janoma
77
@ZachLangley Lo que dices es muy cierto. No hay un pedido total aquí. Probablemente sea peligroso mencionar , pero creo que sirve para construir intuiciones.
Raphael
42

Big O: límite superior

"Big O" ( ) es, con mucho, el más común. Cuando se analiza la complejidad de un algoritmo, la mayoría de las veces, lo que importa es tener un límite superior de la rapidez con que crece el tiempo de ejecución run cuando aumenta el tamaño de la entrada. Básicamente queremos saber que ejecutar el algoritmo no va a tomar "demasiado tiempo". No podemos expresar esto en unidades de tiempo reales (segundos), porque eso dependería de la implementación precisa (la forma en que se escribe el programa, qué tan bueno es el compilador, qué tan rápido es el procesador de la máquina, ...). Así que evaluamos lo que no depende de tales detalles, que es cuánto tiempo lleva ejecutar el algoritmo cuando lo alimentamos con una entrada más grande. Y nos importa principalmente cuando podemos estar seguros de que el programa está terminado, por lo que generalmente queremos saber que tomará tal cantidad de tiempo o menos.O

Decir que un algoritmo tiene un tiempo de ejecución de para un tamaño de entrada significa que existe una constante tal que el algoritmo se completa en la mayoría de los pasos , es decir, el tiempo de ejecución del algoritmo crece como máximo tan rápido como (hasta un factor de escala). Observando el tiempo de ejecución del algoritmo para el tamaño de entrada , significa informalmente que hasta cierto factor de escala.n K KO(f(n))nKf T ( n ) n O ( n ) T ( n ) f ( n )Kf(n)fT(n)nO(n)T(n)f(n)

Límite inferior

A veces, es útil tener más información que un límite superior. es lo contrario de : expresa que una función crece al menos tan rápido como otra. significa que para alguna constante , o dicho de manera informal, hasta a algún factor de escala.O T ( n ) = Ω ( g ( n ) ) T ( N ) K g ( n ) K T ( n ) g ( n )ΩOT(n)=Ω(g(n))T(N)Kg(n)KT(n)g(n)

Cuando el tiempo de ejecución del algoritmo se puede determinar con precisión, combina y : expresa que se conoce la tasa de crecimiento de una función, hasta un factor de escala. significa que para algunas constantes y . Hablando informalmente, hasta cierto factor de escala.O Ω T ( n ) = Θ ( h ( n ) ) K h ( n ) T ( n ) K h ( n ) K K T ( n ) h ( n )ΘOΩT(n)=Θ(h(n))Kh(n)T(n)Kh(n)KKT(n)h(n)

Consideraciones adicionales

El "pequeño" y se usan con mucha menos frecuencia en el análisis de complejidad. El pequeño es más fuerte que el gran ; donde indica un crecimiento que no es más rápido, indica que el crecimiento es estrictamente más lento. Por el contrario, indica un crecimiento estrictamente más rápido.ω o O O o ωoωoOOoω

He sido un poco informal en la discusión anterior. Wikipedia tiene definiciones formales y un enfoque más matemático.

Tenga en cuenta que el uso del signo igual en y similares es un nombre inapropiado. Estrictamente hablando, es un conjunto de funciones de la variable , y deberíamos escribir .T(n)=O(f(n))O(f(n))nTO(f)

Ejemplo: algunos algoritmos de clasificación

Como esto es bastante seco, déjame darte un ejemplo. La mayoría de los algoritmos de clasificación tienen un tiempo de ejecución cuadrático en el peor de los casos, es decir, para una entrada de tamaño , el tiempo de ejecución del algoritmo es . Por ejemplo, la selección de selección tiene un tiempo de ejecución , porque la selección del elemento requiere comparaciones, para un total de comparaciones. De hecho, el número de comparaciones siempre es exactamente , que crece como . Por lo tanto, podemos ser más precisos sobre la complejidad temporal del tipo de selección: es .nO(n2)O(n2)knkn(n1)/2n(n1)/2n2Θ(n2)

Ahora toma el tipo de fusión . La ordenación por fusión también es cuadrática ( ). Esto es cierto, pero no muy preciso. De hecho, la clasificación de fusión tiene un tiempo de ejecución de en el peor de los casos. Al igual que el ordenamiento por selección, el flujo de trabajo del ordenamiento por fusión es esencialmente independiente de la forma de la entrada, y su tiempo de ejecución es siempre hasta un factor multiplicativo constante, es decir, es .O(n2)O(nlg(n))nlg(n)Θ(nlg(n))

A continuación, considere la clasificación rápida . Quicksort es más complejo. Ciertamente es . Además, el peor caso de quicksort es cuadrático: el peor de los casos es . Sin embargo, el mejor caso de clasificación rápida (cuando la entrada ya está ordenada) es lineal: lo mejor que podemos decir para un límite inferior de clasificación rápida en general es . No repetiré la prueba aquí, pero la complejidad promedio de la clasificación rápida (el promedio tomado de todas las permutaciones posibles de la entrada) es .O(n2)Θ(n2)Ω(n)Θ(nlg(n))

Hay resultados generales sobre la complejidad de los algoritmos de clasificación en entornos comunes. Suponga que un algoritmo de clasificación solo puede comparar dos elementos a la vez, con un resultado de sí o no (ya sea o ). Entonces es obvio que el tiempo de ejecución de cualquier algoritmo de clasificación es siempre (donde es el número de elementos para clasificar), porque el algoritmo tiene que comparar cada elemento al menos una vez para saber dónde encajará. Este límite inferior se puede cumplir, por ejemplo, si la entrada ya está ordenada y el algoritmo simplemente compara cada elemento con el siguiente y los mantiene en orden (es decir, las comparaciones ). Lo que es menos obvio es que el tiempo de ejecución máximo es necesariamentexyx>yΩ(n)nn1Ω(nlg(n)) . Es posible que el algoritmo a veces haga menos comparaciones, pero tiene que haber una constante tal que para cualquier tamaño de entrada , haya al menos una entrada en la que el algoritmo haga más de comparaciones La idea de la prueba es construir el árbol de decisión del algoritmo, es decir, seguir las decisiones que el algoritmo toma del resultado de cada comparación. Como cada comparación devuelve un resultado de sí o no, el árbol de decisión es un árbol binario. Hayposibles permutaciones de la entrada, y el algoritmo necesita distinguir entre todas ellas, por lo que el tamaño del árbol de decisión esKnKnlg(n)n!n!. Dado que el árbol es un árbol binario, se necesita una profundidad de para adaptarse a todos estos nodos. La profundidad es el número máximo de decisiones que toma el algoritmo, por lo que ejecutar el algoritmo implica al menos esta cantidad de comparaciones: el tiempo máximo de ejecución es .Θ(lg(n!))=Θ(nlg(n))Ω(nlg(n))

¹ U otro consumo de recursos como el espacio de memoria. En esta respuesta, solo considero el tiempo de ejecución.

Gilles
fuente
1
"Sin embargo, el mejor caso de clasificación rápida (cuando la entrada ya está ordenada) es lineal" ¡este es el peor de los casos!
user5507
@ user5507: En realidad, depende de la estrategia de pivote. Si el primer elemento (o el último) se elige como pivote, tiene razón; pero si elige el elemento medio, o la mediana de primero, medio, último, entonces la entrada ordenada es el mejor caso.
chirlu
"Las pequeñas o y ω se usan con mucha menos frecuencia en el análisis de complejidad". Esto no es cierto en el análisis de complejidad espacial. En el análisis de la complejidad del tiempo, normalmente usa o y ω cuando cuenta operaciones específicas (comparaciones, búsquedas de disco, errores de caché, lo que tiene). Pero dado que siempre puede esperar y comprar una computadora más rápida, el "tiempo de pared" siempre es "hasta un factor constante", por lo que big-O es mucho más común. En el análisis espacial, a menudo hay límites inferiores difíciles debido a la teoría de la información, por lo que es extremadamente común ver el tamaño reportado como "f (n) + o (f (n)) bits" donde f (n) es el límite inferior.
Seudónimo
Si bien lo pienso: si f (n) es un límite inferior teórico sobre el tamaño de alguna estructura de datos, entonces uno que usa f (n) + O (1) (sobrecarga constante) se llama "implícito", uno que usa f (n) + O (f (n)) (sobrecarga relativa constante) se llama "compacto", y uno que usa f (n) + o (f (n)) (sobrecarga relativa se vuelve eventualmente insignificante) se llama "sucinto" ". Buenos términos para saber si alguna vez necesita trabajar en ese espacio.
Seudónimo
17

Por lo general, se usa para establecer límites superiores (una estimación desde arriba), mientras que se usa para establecer límites inferiores (una estimación desde abajo) y se usa cuando coinciden, en cuyo caso puede usar en lugar de ellos (generalmente) para indicar el resultado.OΩΘΘ

Kaveh
fuente
3
"Típicamente"? ¿Se pueden usar para otra cosa?
svick
1
@svick, sí, por ejemplo, que no es una declaración de límite superior. Por una declaración de límite superior quiero decir algo como que expresa un límite superior en . P=DTime(nO(1))f=O(g)f
Kaveh
44
En realidad, Kaveh, esa es una declaración de límite superior. La traducción inglesa propoer de " " es "P es el conjunto de problemas que se pueden resolver utilizando MÁS un número polinómico de operaciones". Si no quiso decir "a lo sumo", debería haber escrito . (Ambas declaraciones son correctas, por supuesto.)P=DTime(nO(1))P=DTime(nΘ(1))
JeffE
@JeffE, lo considero una igualdad entre conjuntos de funciones, pero tienes razón, también se puede considerar como un límite superior en un sentido más general.
Kaveh
@JeffE En realidad, , ya que but . D T I M E ( Θ ( n log n ) ) P D T I M E ( Θ ( n log n ) ) D T I M E ( n Θ ( 1 ) ) = PDTIME(nΘ(1))DTIME(Θ(nlogn))PDTIME(Θ(nlogn))DTIME(nΘ(1))=
David Richerby