La pregunta
¿Cómo encontrar la complejidad temporal de un algoritmo?
¿Qué he hecho antes de publicar una pregunta en SO?
He pasado por esto , este y muchos otros enlaces
Pero en ningún lugar pude encontrar una explicación clara y directa sobre cómo calcular la complejidad del tiempo.
Que sé yo ?
Digamos para un código tan simple como el siguiente:
char h = 'y'; // This will be executed 1 time
int abc = 0; // This will be executed 1 time
Digamos para un bucle como el siguiente:
for (int i = 0; i < N; i++) {
Console.Write('Hello World !');
}
int i = 0; Esto se ejecutará solo una vez . El tiempo se calcula realmente i=0
y no la declaración.
i <N; Esto se ejecutará N + 1 veces
i ++; Esto se ejecutará N veces
Entonces, el número de operaciones requeridas por este ciclo es
{1+ (N + 1) + N} = 2N + 2
Nota: Esto aún puede estar mal, ya que no estoy seguro de mi comprensión sobre el cálculo de la complejidad del tiempo
Qué quiero saber ?
Ok, entonces estos pequeños cálculos básicos creo que los sé, pero en la mayoría de los casos he visto la complejidad del tiempo como
O (N), O (n2), O (log n), O (n!) .... y muchos otros ,
¿Alguien puede ayudarme a entender cómo se calcula la complejidad temporal de un algoritmo? Estoy seguro de que hay muchos novatos como yo que quieren saber esto.
fuente
Console.Write
al calcular la complejidad, eso es cierto, pero también algo irrelevante en este caso, ya que eso solo cambia un factor constante, que big-O ignora (vea las respuestas), por lo que el resultado final sigue siendo una complejidad de O (N).Respuestas:
Suma cuántas instrucciones de máquina ejecutará en función del tamaño de su entrada y luego simplifica la expresión al término más grande (cuando N es muy grande) y puede incluir cualquier factor constante de simplificación.
Por ejemplo, veamos cómo simplificamos
2N + 2
las instrucciones de la máquina para describir esto como justoO(N)
.¿Por qué eliminamos los dos
2
s?Estamos interesados en el rendimiento del algoritmo a medida que N se hace grande.
Considere los dos términos 2N y 2.
¿Cuál es la influencia relativa de estos dos términos cuando N se hace grande? Supongamos que N es un millón.
Entonces, el primer término es de 2 millones y el segundo es de solo 2.
Por esta razón, eliminamos todos los términos, excepto los más grandes, para N. grande
Entonces, ahora hemos pasado de
2N + 2
a2N
.Tradicionalmente, solo estamos interesados en el rendimiento hasta factores constantes .
Esto significa que realmente no nos importa si hay algún múltiplo constante de diferencia en el rendimiento cuando N es grande. La unidad de 2N no está bien definida en primer lugar de todos modos. Entonces podemos multiplicar o dividir por un factor constante para llegar a la expresión más simple.
Entonces se
2N
vuelve justoN
.fuente
Este es un excelente artículo: http://www.daniweb.com/software-development/computer-science/threads/13488/time-complexity-of-algorithm
La respuesta a continuación se copia desde arriba (en caso de que el enlace excelente se rompa)
La métrica más común para calcular la complejidad del tiempo es la notación Big O. Esto elimina todos los factores constantes para que el tiempo de ejecución pueda estimarse en relación con N a medida que N se aproxima al infinito. En general, puedes pensarlo así:
Es constante El tiempo de ejecución de la declaración no cambiará en relación con N.
Es lineal. El tiempo de ejecución del ciclo es directamente proporcional a N. Cuando N se duplica, también lo hace el tiempo de ejecución.
Es cuadrático El tiempo de ejecución de los dos bucles es proporcional al cuadrado de N. Cuando N se duplica, el tiempo de ejecución aumenta en N * N.
Es logarítmico El tiempo de ejecución del algoritmo es proporcional al número de veces que N puede dividirse entre 2. Esto se debe a que el algoritmo divide el área de trabajo por la mitad con cada iteración.
Es N * log (N). El tiempo de ejecución consta de N bucles (iterativos o recursivos) que son logarítmicos, por lo que el algoritmo es una combinación de lineal y logarítmico.
En general, hacer algo con cada elemento en una dimensión es lineal, hacer algo con cada elemento en dos dimensiones es cuadrático, y dividir el área de trabajo por la mitad es logarítmico. Existen otras medidas de Big O como la raíz cúbica, exponencial y cuadrada, pero no son tan comunes. La notación O grande se describe como
O ( <type> )
dónde<type>
está la medida. El algoritmo de clasificación rápida se describiría comoO ( N * log ( N ) )
.Tenga en cuenta que nada de esto ha tenido en cuenta las mejores, medias y peores medidas. Cada uno tendría su propia notación Big O. También tenga en cuenta que esta es una explicación MUY simplista. Big O es el más común, pero también es más complejo de lo que he mostrado. También hay otras anotaciones como omega grande, o pequeña y theta grande. Probablemente no los encontrará fuera de un curso de análisis de algoritmos. ;)
fuente
Tomado de aquí: Introducción a la complejidad temporal de un algoritmo
1. Introducción
En informática, la complejidad temporal de un algoritmo cuantifica la cantidad de tiempo que tarda un algoritmo en ejecutarse en función de la longitud de la cadena que representa la entrada.
2. Gran notación O
La complejidad de tiempo de un algoritmo se expresa comúnmente usando una notación O grande, que excluye coeficientes y términos de orden inferior. Cuando se expresa de esta manera, se dice que la complejidad del tiempo se describe asintóticamente, es decir, a medida que el tamaño de entrada llega al infinito.
Por ejemplo, si el tiempo requerido por un algoritmo en todas las entradas de tamaño n es como máximo 5n 3 + 3n, la complejidad del tiempo asintótico es O (n 3 ). Más sobre eso más tarde.
Pocos ejemplos más:
3. O (1) Tiempo constante:
Se dice que un algoritmo se ejecuta en tiempo constante si requiere la misma cantidad de tiempo, independientemente del tamaño de entrada.
Ejemplos:
4. O (n) Tiempo lineal
Se dice que un algoritmo se ejecuta en tiempo lineal si su ejecución de tiempo es directamente proporcional al tamaño de entrada, es decir, el tiempo crece linealmente a medida que aumenta el tamaño de entrada.
Considere los siguientes ejemplos, a continuación estoy buscando linealmente un elemento, esto tiene una complejidad temporal de O (n).
Más ejemplos:
5. O (log n) Tiempo logarítmico:
Se dice que un algoritmo se ejecuta en tiempo logarítmico si su ejecución de tiempo es proporcional al logaritmo del tamaño de entrada.
Ejemplo: búsqueda binaria
Recuerde el juego de las "veinte preguntas": la tarea es adivinar el valor de un número oculto en un intervalo. Cada vez que hace una suposición, le dicen si su suposición es demasiado alta o demasiado baja. El juego de veinte preguntas implica una estrategia que utiliza su número de conjetura para reducir a la mitad el tamaño del intervalo. Este es un ejemplo del método general de resolución de problemas conocido como búsqueda binaria.
6. O (n 2 ) Tiempo cuadrático
Se dice que un algoritmo se ejecuta en tiempo cuadrático si su ejecución de tiempo es proporcional al cuadrado del tamaño de entrada.
Ejemplos:
7. Algunos enlaces útiles
fuente
Aunque hay algunas buenas respuestas para esta pregunta. Me gustaría dar otra respuesta aquí con varios ejemplos de
loop
.O (n) : la complejidad temporal de un bucle se considera como O (n) si las variables del bucle se incrementan / disminuyen en una cantidad constante. Por ejemplo, las siguientes funciones tienen una complejidad de tiempo O (n) .
O (n ^ c) : la complejidad temporal de los bucles anidados es igual al número de veces que se ejecuta la instrucción más interna. Por ejemplo, los siguientes bucles de muestra tienen una complejidad de tiempo O (n ^ 2)
Por ejemplo, el orden de selección y el orden de inserción tienen una complejidad de tiempo O (n ^ 2) .
O (Logn) La complejidad del tiempo de un ciclo se considera como O (Logn) si las variables del ciclo se dividen / multiplican por una cantidad constante.
Por ejemplo, la búsqueda binaria tiene una complejidad de tiempo O (Logn) .
O (LogLogn) La complejidad del tiempo de un ciclo se considera como O (LogLogn) si las variables del ciclo se reducen / aumentan exponencialmente en una cantidad constante.
Un ejemplo de análisis de complejidad temporal.
Análisis :
For i = 1, the inner loop is executed n times. For i = 2, the inner loop is executed approximately n/2 times. For i = 3, the inner loop is executed approximately n/3 times. For i = 4, the inner loop is executed approximately n/4 times. ……………………………………………………. For i = n, the inner loop is executed approximately n/n times.
Entonces, la complejidad de tiempo total del algoritmo anterior es
(n + n/2 + n/3 + … + n/n)
, que se convierte enn * (1/1 + 1/2 + 1/3 + … + 1/n)
Lo importante de las series
(1/1 + 1/2 + 1/3 + … + 1/n)
es igual a O (Logn) . Entonces, la complejidad temporal del código anterior es O (nLogn) .Ref: 1 2 3
fuente
Complejidad del tiempo con ejemplos
1 - Operaciones básicas (aritmética, comparaciones, acceso a elementos de la matriz, asignación): el tiempo de ejecución siempre es constante O (1)
Ejemplo:
2 - Si la declaración de lo contrario: solo toma el tiempo de ejecución máximo de dos o más declaraciones posibles.
Ejemplo:
Entonces, la complejidad del pseudocódigo anterior es T (n) = 2 + 1 + max (1, 1 + 2) = 6. Por lo tanto, su gran oh sigue siendo constante T (n) = O (1).
3 - Bucle (para, mientras, repetir): el tiempo de ejecución de esta instrucción es el número de bucles multiplicado por el número de operaciones dentro de ese bucle.
Ejemplo:
Entonces, su complejidad es T (n) = 1 + 4n + 1 = 4n + 2. Por lo tanto, T (n) = O (n).
4 - Bucle anidado (bucle dentro de bucle): dado que hay al menos un bucle dentro del bucle principal, el tiempo de ejecución de esta instrucción utilizó O (n ^ 2) u O (n ^ 3).
Ejemplo:
Tiempo de funcionamiento común
Existen algunos tiempos de ejecución comunes al analizar un algoritmo:
O (1) - Tiempo constante El tiempo constante significa que el tiempo de ejecución es constante, no se ve afectado por el tamaño de entrada .
O (n) - Tiempo lineal Cuando un algoritmo acepta n tamaño de entrada, también realizaría n operaciones.
O (log n) - Algoritmo de tiempo logarítmico que tiene tiempo de ejecución O (log n) es un poco más rápido que O (n). Comúnmente, el algoritmo divide el problema en subproblemas con el mismo tamaño. Ejemplo: algoritmo de búsqueda binaria, algoritmo de conversión binaria.
O (n log n) - Tiempo lineal lineal Este tiempo de ejecución se encuentra a menudo en "algoritmos de división y conquista" que dividen el problema en subproblemas de forma recursiva y luego los fusionan en n tiempo. Ejemplo: algoritmo Merge Sort.
O (n 2 ) - ¡Algoritmo de clasificación de burbujas de aspecto de tiempo cuadrático!
O (n 3 ) - Tiempo cúbico Tiene el mismo principio con O (n 2 ).
O (2 n ) - Tiempo exponencial Es muy lento a medida que la entrada aumenta, si n = 1000,000, T (n) sería 21000,000. El algoritmo de fuerza bruta tiene este tiempo de ejecución.
O (n!) - Tiempo factorial ¡¡¡LO MÁS LENTO !!! Ejemplo: Problema de vendedor de viajes (TSP)
Tomado de este artículo . Muy bien explicado debería dar una lectura.
fuente
visitors = visitors + 1
es1 + 1 = 2
. ¿Podrías explicarme por qué hiciste eso?visitors + 1
Segundo paso: asignar valor desde el primer paso avisitors
So, la expresión anterior está formada por dos declaraciones; primer paso + segundo paso => 1 + 1 = 2age = read(x) // (1+1) = 2
age = read(x) // (1+1) = 2
read(x) // O(1) a = 10; // O(1)
Primero es la función call => O (1) ///// Segundo es la asignación, como dijo nbro, pero 10 es constante, entonces el segundo es => O (1) ...Cuando analiza el código, debe analizarlo línea por línea, contando cada operación / reconociendo la complejidad del tiempo, al final, debe sumarlo para obtener una imagen completa.
Por ejemplo, puede tener un bucle simple con complejidad lineal , pero más adelante en ese mismo programa puede tener un bucle triple que tiene complejidad cúbica , por lo que su programa tendrá complejidad cúbica . El orden de crecimiento de las funciones entra en juego aquí.
Veamos cuáles son las posibilidades de complejidad de tiempo de un algoritmo, puede ver el orden de crecimiento que mencioné anteriormente:
Constante de tiempo tiene un orden de crecimiento
1
, por ejemplo:a = b + c
.El tiempo logarítmico tiene un orden de crecimiento
LogN
, generalmente ocurre cuando se divide algo por la mitad (búsqueda binaria, árboles, incluso bucles) o cuando se multiplica algo de la misma manera.Lineal , el orden de crecimiento es
N
, por ejemploEl orden de crecimiento lineal es
n*logN
, generalmente, ocurre en algoritmos de división y conquista.El
N^3
ejemplo clásicode orden de crecimiento cúbico es un ciclo triple donde se verifican todos los trillizos:El orden de crecimiento exponencial
2^N
generalmente ocurre cuando realiza una búsqueda exhaustiva, por ejemplo, verifica los subconjuntos de algún conjunto.fuente
Hablando en términos generales, la complejidad del tiempo es una forma de resumir cómo crece el número de operaciones o el tiempo de ejecución de un algoritmo a medida que aumenta el tamaño de entrada.
Como la mayoría de las cosas en la vida, un cóctel puede ayudarnos a entender.
EN)
Cuando llegas a la fiesta, tienes que estrechar la mano de todos (hacer una operación en cada elemento). A medida que
N
aumenta el número de asistentes , el tiempo / trabajo que le llevará estrechar la mano de todos aumenta a medida queO(N)
.¿Por qué
O(N)
y nocN
?Existe una variación en la cantidad de tiempo que se necesita para estrechar la mano de las personas. Podría promediar esto y capturarlo de manera constante
c
. Pero la operación fundamental aquí, estrechar la mano de todos, siempre sería proporcionalO(N)
, sin importar lo quec
fuera. Al debatir si deberíamos ir a una fiesta de cócteles, a menudo estamos más interesados en el hecho de que tendremos que conocer a todos que en los detalles minuciosos de cómo son esas reuniones.O (N ^ 2)
El anfitrión del cóctel quiere que juegues un juego tonto donde todos se encuentran con todos los demás. Por lo tanto, debe conocer a
N-1
otras personas y, debido a que la siguiente persona ya lo ha conocido, debe conocer a otrasN-2
personas, y así sucesivamente. La suma de esta serie esx^2/2+x/2
. A medida que crece el número de asistentes, elx^2
término se hace grande rápidamente , por lo que simplemente dejamos todo lo demás.O (N ^ 3)
Debe conocer a todos los demás y, durante cada reunión, debe hablar sobre todos los demás en la sala.
O (1)
El anfitrión quiere anunciar algo. Beben una copa de vino y hablan en voz alta. Todos los oyen. Resulta que no importa cuántos asistentes haya, esta operación siempre toma la misma cantidad de tiempo.
O (log N)
El anfitrión ha colocado a todos en la mesa en orden alfabético. ¿Donde esta Dan? Usted razona que debe estar en algún lugar entre Adam y Mandy (¡ciertamente no entre Mandy y Zach!). Dado eso, ¿está entre George y Mandy? No. Debe estar entre Adam y Fred, y entre Cindy y Fred. Y así sucesivamente ... podemos localizar eficientemente a Dan mirando la mitad del conjunto y luego la mitad de ese conjunto. Finalmente, nos fijamos en los individuos O (log_2 N) .
O (N log N)
Puede encontrar dónde sentarse en la mesa utilizando el algoritmo anterior. Si un gran número de personas se acercara a la mesa, una a la vez, y todas hicieran esto, eso llevaría tiempo O (N log N) . Esto resulta ser cuánto tiempo lleva ordenar una colección de artículos cuando deben compararse.
Mejor / peor caso
Llegas a la fiesta y necesitas encontrar a Iñigo: ¿cuánto tiempo te llevará? Depende de cuando llegues. Si todo el mundo está dando vueltas, has tocado el peor de los casos: tomará
O(N)
tiempo. Sin embargo, si todos están sentados a la mesa, solo tomaráO(log N)
tiempo. O tal vez pueda aprovechar el poder de gritos de copa de vino del anfitrión y solo tomaráO(1)
tiempo.Suponiendo que el anfitrión no esté disponible, podemos decir que el algoritmo de búsqueda de Íñigo tiene un límite inferior
O(log N)
y un límite superiorO(N)
, según el estado de la fiesta cuando llegue.Espacio y comunicación
Se pueden aplicar las mismas ideas para comprender cómo los algoritmos usan el espacio o la comunicación.
Knuth ha escrito un buen artículo sobre el anterior titulado "La complejidad de las canciones" .
fuente
Sé que esta pregunta se remonta y hay algunas respuestas excelentes aquí, sin embargo, quería compartir un poco más para las personas con mentalidad matemática que tropezarán en esta publicación. El teorema de Master es otra cosa útil para saber cuando se estudia la complejidad. No lo vi mencionado en las otras respuestas.
fuente
O (n) es una notación O grande utilizada para escribir la complejidad del tiempo de un algoritmo. Cuando sumas el número de ejecuciones en un algoritmo obtendrás una expresión en resultado como 2N + 2, en esta expresión N es el término dominante (el término que tiene mayor efecto en la expresión si su valor aumenta o disminuye). Ahora O (N) es la complejidad del tiempo mientras N es el término dominante. Ejemplo
aquí el número total de ejecuciones para el bucle interno es n + 1 y el número total de ejecuciones para el bucle externo es n (n + 1) / 2, por lo que el número total de ejecuciones para todo el algoritmo es n + 1 + n (n + 1/2 ) = (n ^ 2 + 3n) / 2. aquí n ^ 2 es el término dominante, por lo que la complejidad de tiempo para este algoritmo es O (n ^ 2)
fuente