¿Cómo evaluar la complejidad temporal de un algoritmo?

1. Comparación de los dos algoritmos

¿Conoces la historia del matemático Gauss sobre 1+2+3+…+100?

Gauss comenzó la escuela cuando tenía 7 años. Cuando tenía 10 años, una vez que un maestro quería tratar con los estudiantes traviesos de la clase, les dio un problema de matemáticas y les pidió a los estudiantes que sumaran desde 1+2+3... hasta 100. Pensó que esta pregunta era suficiente para que los estudiantes contaran por medio día, y él también podría tener medio día libre. Quién sabe, más allá de sus expectativas, solo un tiempo después. El pequeño Gauss levantó la mano y dijo que había terminado. Cuando el maestro vio la respuesta, 5050, era completamente correcta y el maestro quedó asombrado. Cuando se le preguntó qué tan poco calculó Gauss, Gauss dijo que no sumó desde el principio hasta el final, sino que primero sumó 1 y 100 para obtener 101, luego sumó 2 y 99, y también obtuvo 101, y finalmente 50 y 51 se sumaron juntos Además, tiene que ser 101, por lo que hay 50 101 en total, y el resultado es, por supuesto, 5050. El profesor elogió al inteligente Gauss.

¿Cómo escribiste por primera vez el algoritmo para sumar 1 a 100? ¿Déjame adivinar?

int sum=0;
for(int i=1;i<=100;i++){
    
    
    sum = sum +i;
}
retrun sum;

Bajo el rápido poder de cómputo de la computadora, el resultado es 5050.
Pero para Gauss, un niño prodigio es un niño prodigio, y dio otra respuesta más perfecta:

sum=0,n=100;
sum=(i+n)*n/2
retrun sum;

El primer método, si se usa para calcular del 1 al 100, entonces necesita hacer un bucle 100 veces, si se calcula hasta 100 millones, necesita hacer un bucle 100 millones de veces, y el siguiente método, sin importar cuánto se agregue, ¡Solo necesita ejecutarse una vez!

2. Eficiencia algorítmica y métodos de medición

Los dos algoritmos anteriores, ¿cómo sabemos que el segundo algoritmo es mejor que el primero?
A continuación se describen dos métodos para medir la eficiencia de los algoritmos.

2.1 Medición ex-post

El método de medición post-mortem, como sugiere el nombre, es juzgar la eficiencia del algoritmo a través del tiempo de ejecución del algoritmo después de que se ejecuta el algoritmo.

Suena genial, pero básicamente muy pocos algoritmos pueden evaluarse después del hecho. ¿Por qué?

  • Necesidad de escribir un buen código: después del método de medición, debe medirse en función del código en ejecución. Si el resultado de la medición muestra que el algoritmo es malo, el proceso escrito previamente es básicamente en vano.
  • Depende del entorno operativo: el resultado de cada medición tiene una gran relación con el estado de la computadora que ejecuta el algoritmo. Las computadoras con diferentes configuraciones, como Sunway TaihuLight y las computadoras comunes, ejecutan el mismo programa y el tiempo de ejecución variará mucho. Incluso si se trata de la misma computadora, el uso de la CPU y la memoria de la computadora no es el mismo en diferentes períodos de tiempo, lo que es fácil de causar errores.
  • Dificultad en el diseño de datos de prueba: para probar si un algoritmo es bueno o no, no basta con ejecutarlo solo una vez. A menudo, se requiere una gran cantidad de datos de prueba para ejecutarse continuamente para ver la brecha entre ellos, como diferentes algoritmos de clasificación. , ordenar 10 números, básicamente no hay diferencia en los resultados de la ejecución, pero si ordena datos de 100w, habrá un intervalo de tiempo, pero es muy problemático preparar datos de 100w.

2.2 Método de medición ex ante

Métricas ex ante: evalúe la eficiencia del algoritmo antes de codificar.
Es increíble, el algoritmo se evalúa antes de escribir el código, ¿cómo se puede hacer?
Porque para los programas escritos en lenguajes de alto nivel, el tiempo que tarda el programa en ejecutarse en la computadora depende de los siguientes factores:

  1. El método de estrategia adoptado por el algoritmo.
  2. Calidad del código compilado
  3. el tamaño de entrada del problema
  4. La velocidad a la que la máquina ejecuta las instrucciones La
    segunda está respaldada por el software compilado y la cuarta está determinada por el hardware de la computadora.

Por lo tanto, además de la interferencia de software y hardware, la calidad del algoritmo debería depender de la escala de la entrada del problema: si el algoritmo es bueno o malo.
Veamos los dos algoritmos anteriores.

int sum=0;   //执行一次
for(int i=1;i<=100;i++){
    
    
    sum = sum +i;  //执行n次
}
retrun sum; //执行1次

El primer algoritmo se ejecuta n+2 veces en total
¿Qué pasa con el segundo algoritmo? 1+1+1=3 veces

sum=0,n=100;  //一次
sum=(i+n)*n/2  //一次
retrun sum; //一次

Ignoramos el mismo código en la primera y última línea.La eficiencia de ejecución de estos dos algoritmos es la diferencia entre 1 y n veces. Los veo a todos.

3. Crecimiento incremental de la función

Si tenemos 4 algoritmos, sus entradas son todas n y el número de ejecuciones es 2n, 2n+3, 3n, 3n+1, ¿cuál algoritmo es más eficiente?

norte 2n 2n+3 3n 3n+1
1 2 5 3 4
2 4 7 6 7
3 6 9 9 10
10 20 23 30 31
100 200 203 300 301
1000 2000 2003 3000 30001

¿Encontró qué? Cuando n es relativamente pequeño, los tiempos de ejecución de los cuatro algoritmos son casi iguales Incluso cuando n=1, 3n y 3n+1 son más eficientes que 2n+1, pero a medida que n aumenta, la función 2n y 2n+3 son significativamente más eficiente que 3n+1.
Entonces concluimos que los algoritmos 2n y los algoritmos 2n+3 funcionan mejor que los algoritmos 3n y 3n+1 .

Observando cuidadosamente 2n y 2n+3, encontraremos que a medida que aumenta el número de ejecuciones, la siguiente constante 3 tiene menos impacto en la eficiencia de ejecución general, por lo que estamos sacando una conclusión:
los algoritmos 2n y 2n+3 tienen la misma ejecución eficiencia _
Veamos el segundo ejemplo:
el número de ejecuciones de un algoritmo es 4n+8, y el número de ejecuciones de un algoritmo es 2n 2 +1, ¿cuál es el número de ejecuciones entre ellos?

norte 4n + 8 2n 2 +1
1 12 3
2 dieciséis 9
3 20 19
10 48 201
100 408 20001
1000 4008 2000001

A medida que n continúa aumentando, la diferencia en el número de ejecuciones de los dos algoritmos también aumenta.Después de una observación cuidadosa, se encuentra que la razón de esta brecha proviene del método del cuadrado de n, y las constantes 2 y 4 tienen un impacto en general, es mucho menor que n al cuadrado, por lo que nuevamente concluimos que la función multiplicada por el término de mayor orden no es importante en el algoritmo .
Esto también muestra que la eficiencia de ejecución del Algoritmo 2n y el Algoritmo 3n pueden considerarse iguales, y pueden considerarse como n.
Finalmente, veamos un ejemplo:
un algoritmo se ejecuta 2n 2 +3n+1, uno es 2n 3 +3n+1, y sus tiempos de ejecución son

norte 2n 2 +3n+1 2n 3 +3n+1
1 6 6
2 15 23
3 28 64
10 231 2031
100 2031 2000301

A medida que el valor de n se hace más y más grande, el efecto de los siguientes 3n+1 en el número de ejecuciones se puede ignorar básicamente, por lo que se concluye que al comparar los dos algoritmos, solo se necesita comparar el elemento de mayor orden
. el final El término de orden más alto de , denotado como la complejidad temporal de la función O.
Tiempos de ejecución 2n+1, denotados como f complejidad O(n)
Tiempos de ejecución 2n 2 +n+3, denotados como complejidad de tiempo O(n 2 ),
y el algoritmo sin n, como el segundo cálculo 1 El algoritmo agregado a 100 solo debe ejecutarse tres veces. La complejidad temporal de este algoritmo se registra uniformemente como O(1)

4. Complejidad del tiempo común

orden lineal

La complejidad temporal del siguiente código es n, porque el código lógico se ejecuta n veces en el cuerpo del bucle, y esta complejidad temporal se denomina orden lineal.

for(int i=0;i<n;i++){
    
    
//执行逻辑代码		
}

logarítmico

Mirando el siguiente código, después de cada conteo*2, estará más cerca de n Supongamos que
2 x = n después de ejecutar x, luego el número de ejecuciones x = log 2 n, y su complejidad de tiempo es O (log 2 n)

int count=1;
while(count<n){
    
    
    count=count*2;	
}

Orden cuadrado

Este tipo de bucle está anidado, el número de ejecuciones es n 2 y la complejidad del tiempo es n 2

for(int i=0;i<n;i++){
    
    
    for(int j=0;j<n;j++){
    
    
     //逻辑
    }
}

5. Peor caso y mejor caso

A veces, queremos encontrar un número determinado en una matriz aleatoria de n números, buscamos en orden, tal vez el primer número sea el valor que estamos buscando, la complejidad de tiempo sea O(1), o puede ser el último , grado de complejidad temporal O(n), llamamos al primer caso la mejor complejidad temporal y al segundo caso la peor complejidad temporal. Cuando evaluamos un algoritmo, a menudo consideramos el peor de los casos 1. Por lo tanto, en general, sin instrucciones especiales, la complejidad temporal es la peor complejidad temporal.

Supongo que te gusta

Origin blog.csdn.net/qq_45171957/article/details/123774115
Recomendado
Clasificación