Estructura de datos y análisis de complejidad temporal del algoritmo-01

Análisis de complejidad del tiempo

1. Pensando

  • Algoritmo (Algoritmo) se refiere a un conjunto de métodos utilizados para manipular datos y resolver problemas de programa. Para un mismo problema, utilizando diferentes algoritmos, el resultado final puede ser el mismo, pero los recursos y el tiempo consumidos en el proceso serán muy diferentes.
    Por ejemplo, para atornillar una tuerca, tanto una llave inglesa como unos alicates pueden hacer el trabajo, pero usar una llave para atornillar una tuerca es definitivamente más eficiente.
  • Entonces, ¿cómo medimos los pros y los contras de diferentes algoritmos?
  1. Método estadístico posterior al evento
    A través de estadísticas y monitoreo, el tiempo de ejecución del algoritmo y la memoria ocupada son los más precisos, pero existen grandes limitaciones:
    Los resultados de una prueba dependen mucho del entorno de
    prueba Los resultados de la prueba B se ven muy afectados por la escala de los datos
  2. Analiza y estima de antemano.
    Piensa en ello. Cuando queremos implementar una función, esperamos conocer rápidamente la solución óptima entre varias soluciones y luego implementarla, en lugar de hacer grandes esfuerzos para hacer cada solución y luego probarla. Como resultado , es demasiado ineficiente.
    Por lo tanto, debemos evaluar los factores que afectan la eficiencia del código (como el tiempo, la complejidad del espacio, etc.) antes de que se ejecute el código. Por tanto, necesitamos tomar decisiones a través del análisis de complejidad, a continuación explicamos principalmente la complejidad temporal más frecuente en la entrevista.
    Inserte la descripción de la imagen aquí

Dos, introducción a la complejidad del tiempo

concepto

¿Cuál es la complejidad del tiempo? Primero entendamos esto con un fragmento de código:

int sum(int n){
    
    
    int sum = 0; 
    int i = 1; 
    for(;i<=n;++i){
    
    
        sum=sum+i; 
    }
    return sum;
}
  • Este código es un programa para operaciones de suma. El tiempo que tarda la computadora en ejecutar cada línea de código es casi el mismo. Si usamos una variable time para representar el tiempo de ejecución de cada línea de código, el tiempo total del método de suma es calculado de la siguiente manera:
    • La segunda línea de código se ejecuta solo una vez.
    • La tercera línea de código se ejecuta solo una vez.
    • La línea 4 debe ejecutarse n veces porque necesita repetir n veces, y toma n * tiempo
    • La línea 5 debe ejecutarse n veces porque necesita repetir n veces, y toma n * tiempo
  • El resultado final es 2n × tiempo + 2 × tiempo, que es 2 (n + 1) × tiempo. En otras palabras: el tiempo total de ejecución del código = el tiempo de ejecución de una línea de código × cuántas líneas de código se ejecutan en total

para resumir

  1. Dado que el tiempo puede considerarse fijo, el tiempo total de ejecución del código es proporcional al número de ejecuciones de código. Por lo tanto, siempre que juzguemos el número de ejecuciones, conoceremos el tiempo total de ejecución del código. Podemos analizar los pros y los contras del programa siempre que prestemos atención al número de ejecuciones de código.
  2. Cuando denotamos el tiempo total de ejecución del código como T (n), la relación proporcional se denota con O, y el número total de líneas de código ejecutadas se denota con fn (), obtenemos una fórmula común. Esta forma de expresar la complejidad del tiempo del código se denomina notación de complejidad del tiempo Big O.

Tn = O (fn ())

  1. Nota: Debido a que O no representa el tiempo real de ejecución del código, sino que solo representa una tendencia creciente, se denomina complejidad de tiempo progresiva o complejidad de tiempo para abreviar.
  2. Cuando n es grande, la constante / coeficiente / orden bajo no afectará la tendencia de crecimiento, por lo que se ignorará al calcular la complejidad del tiempo y solo se registrará la magnitud más grande. Por lo tanto, la complejidad del tiempo del código anterior ignora las constantes y coeficientes, y finalmente Tn = O (n)

Inserte la descripción de la imagen aquí

3. Habilidades de análisis y complejidad del tiempo común

La complejidad de tiempo común en orden descendente es: Ο (1) < Ο (logn) < Ο (n) < Ο (nlogn) < Ο (n ^ 2) < Ο (n ^ 3) < Ο (2 ^ n) < Ο (¡n!), La complejidad del tiempo es cada vez mayor y la eficiencia de ejecución es cada vez menor. Los siguientes ejemplos se explican a su vez

1. Orden constante O (1)

  • Siempre que no haya una estructura compleja, como bucles, el código no crecerá con el crecimiento de la variable cuando se ejecute el código, entonces la complejidad del código es O (1) sin importar la longitud del código, como :
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

2. Orden lineal O (n)

  • "Bucle de un nivel", el número de operaciones que el algoritmo necesita realizar está representado por una función del tamaño de entrada n, es decir, O (n).
for(int i=1;i<=n;i++){
    
    
  System.out.println(i);
}
for(int i=1;i<=n;i++){
    
    
  System.out.println(i);
}
  • Nota: Debido a que el bucle for del código no está anidado, el número de ejecuciones es 2 * n, que es O (2n), y la constante ignorante es O (n).

3. Orden logarítmico O (logN)

  • Comprender a través del código:
int i = 1;
while(i<n){
    
    
    i = i * 2;
}
  • Analizamos la complejidad temporal del código anterior principalmente para ver cuántas veces se ejecuta el código.
  • Supongamos que i> = n después de repetir x veces, porque cada vez que se multiplica por 2, la potencia x de 2 es> = n, y se obtiene la fórmula 2 ^ x> = n. Entonces x = log n, que es el logaritmo de n basado en dos. Aplique la notación Big O, la complejidad del tiempo es O (log n)

4. Orden logarítmico lineal O (nlogN)

  • nlog n = n * log n, por lo que es equivalente a reciclar nuestro código de caso anterior n veces, por lo que la complejidad de tiempo del siguiente código es O (nlog n):
for(m=1; m<n; m++){
    
    
    i = 1;
    while(i<n){
    
    
        i = i * 2;
    }
}

5. Orden cuadrado O (n ^ 2)

  • Una capa de bucle se ejecuta n veces, n * n son dos capas de bucle, por lo que se puede entender combinando el siguiente código
for(x=1; i<=n; x++){
    
    
   for(i=1; i<=n; i++){
    
    
       j = i;
       j++;
    }
}

6. En otros casos, etc.

  • El orden cúbico O (n³) es equivalente a tres capas de n ciclos, pero O (n³) n demasiado grande hará que el resultado sea poco realista, y el mismo O (2 ^ n) y O (n!) A menos que sea un pequeño n De lo contrario, incluso si n es solo 100, el tiempo de ejecución es una pesadilla, por lo que generalmente no se discute la complejidad del tiempo de este algoritmo.

Cuarto, habilidades de análisis de la complejidad del tiempo

A través del ejemplo anterior, me pregunto si ha descubierto un patrón determinado:

  1. La complejidad del código anidado es igual al producto de la complejidad del código dentro y fuera del nido.
  2. Solo preste atención al código con la mayoría de las ejecuciones de bucle, porque ignoraremos las constantes, los niveles bajos y los coeficientes en la fórmula.

Cinco, preguntas de la entrevista para practicar las manos.

Inserte la descripción de la imagen aquí
Tema: Suponga que la ecuación recursiva de la función de complejidad de tiempo de un algoritmo es T (n) = T (n-1) + n (n es un número entero positivo) y T (0) = 1, entonces la complejidad de tiempo del algoritmo es ().

  • A. O (registro)
  • B. O (nlogn)
  • C. O (n)
  • D. O (n ^ 2)

La última respuesta es D ~

para resumir

  • La complejidad del tiempo se acabó. De hecho, hay más complejidad de tiempo promedio en profundidad, complejidad de tiempo amortizado, complejidad de mejor tiempo, peor complejidad de tiempo, etc., si tiene tiempo y lo necesita, puede escribir sobre ello.
  • Mientras me consolido, también espero ayudar a todos ~

Supongo que te gusta

Origin blog.csdn.net/Cathy_2000/article/details/114240964
Recomendado
Clasificación