Cómo juzgar la calidad de un algoritmo

1. Introducción

        Un algoritmo excelente debe satisfacer la corrección, la legibilidad, la solidez y la eficiencia. En términos generales, los tres primeros son más fáciles de lograr. La eficiencia no es fácil de descubrir para los propios desarrolladores. La baja eficiencia no es terrible. Lo terrible es que las personas que escriben el código no conocen la baja eficiencia. Los diferentes algoritmos tienen un gran impacto en el rendimiento. Este artículo analiza la eficiencia.

2. Obtener eficiencia mediante pruebas reales

        Utilice métodos de prueba para calcular con precisión el tiempo de ejecución del algoritmo.

ventaja:

        Se puede obtener el tiempo de ejecución específico del algoritmo.

defecto:

        (1) El algoritmo se ve afectado por diferentes dispositivos y diferentes dispositivos pueden agotarse en diferentes momentos, lo que en última instancia conduce a resultados poco confiables;

        (2) Si el algoritmo lleva mucho tiempo, debe esperar hasta que se complete el cálculo para obtener el resultado, lo cual es una pérdida de tiempo;

3. Utilice conocimientos teóricos para analizar la eficiencia de antemano.

        Hay dos tipos de análisis de eficiencia de algoritmos: el primero es la eficiencia del tiempo y el segundo es la eficiencia del espacio. La eficiencia del tiempo se llama complejidad del tiempo, mientras que la eficiencia del espacio se llama complejidad del espacio. La complejidad del tiempo mide principalmente la velocidad de ejecución de un algoritmo, mientras que la complejidad del espacio mide principalmente el espacio adicional requerido por un algoritmo. A veces, la eficiencia del tiempo y la eficiencia del espacio son contradictorias. Si quieres tiempo, tienes que sacrificar espacio, si quieres espacio, Tenemos que sacrificar espacio, sacrificar tiempo, que a menudo se dice que es espacio por tiempo/tiempo por espacio.

        En los primeros días del desarrollo informático, las computadoras tenían muy poca capacidad de almacenamiento. Por eso nos preocupamos mucho por la complejidad del espacio. Sin embargo, tras el rápido desarrollo de la industria informática, la capacidad de almacenamiento de las computadoras ha alcanzado un nivel muy alto. Así que ahora ya no necesitamos prestar especial atención a la complejidad espacial de un algoritmo, este artículo habla principalmente de la complejidad temporal.

3.1 Concepto:

        El tiempo que tarda un algoritmo es proporcional al número de ejecuciones de sus declaraciones. El número de ejecuciones de operaciones básicas en el algoritmo es la complejidad temporal del algoritmo.

3.2 Método de representación:

        El uso de la notación O grande para describir el comportamiento asintótico de funciones tiene los siguientes tipos principales de complejidad:

        

        Al escribir algoritmos, deberíamos intentar elegir una complejidad temporal que suavice la curva.

        

3.2.1.Constante O(1)

  • Comúnmente utilizado en operaciones simples como asignación y referencia.
  • El consumo del algoritmo no aumenta con el crecimiento de las variables y el rendimiento es el mejor.
  • No importa cuántas líneas de código se ejecuten, incluso si hay decenas de miles de líneas, la complejidad temporal es O (1)
  • En el proceso de desarrollo real, la complejidad temporal de una recursión también es O (1). Porque O(1^n) es O(1) sin importar cuánto sea n
int i = 1;
int j = 2;
i++;
j--;
int k = i + j;

Análisis de código: i es 1, j es 2 y k es 3. La complejidad del tiempo es O (1).

3.2.2 Logarítmico O(log n)

  • El número de tiempos de ejecución del código de uso común es x y n es el número objetivo. De acuerdo con 2^x=n, se deduce que x=log2(n) (log n)
  • El consumo del algoritmo aumenta con el aumento de n y el rendimiento es mejor.
int i = 100;
int j = 1;
while(j < i){
    j = j * 2
}

Análisis de código: j es 128. Cuando i es 100, la complejidad del tiempo es O (log2 (100)). Desde Math.log2(100)≈6,64, la complejidad temporal final es O (6,65).

3.2.3 Lineal O(n)

  • Comúnmente visto en un bucle for, bucle while
  • El consumo del algoritmo aumenta con el aumento de n y el rendimiento es medio.
  • No importa cuán grande sea el valor de n, la complejidad del tiempo es O (n)
int n = 100;
int j = 0;
for(int i = 0; i < n; i++){
    j = i;
}

Análisis de código: i es 100 y j es 99. n es 100, la complejidad del tiempo es O (100).

3.2.4 Logarítmico lineal O(n log n)

  • A menudo se utiliza para ejecutar un bucle n veces en código con una complejidad temporal de O(log2(n))
  • El consumo del algoritmo aumenta con el aumento de n y el rendimiento es deficiente.
int n = 100;
for(int m = 0; m < n; m++){
    int i = 1;
    while(i < n){
        i = i * 2
    }
}

Análisis de código: i es 128. m es 100, n es 100 y la complejidad del tiempo es O (m log2 (n)). Debido a que 100* Math.log2(100)≈664,39, la complejidad temporal final es O (664,39).

3.2.5 Tipo cuadrado O(n^2), tipo cúbico O(n^3), tipo K-ésimo de potencia O(n^k)

  • La complejidad del tiempo del algoritmo más común, que se puede utilizar para desarrollar rápidamente la lógica empresarial.
  • Comúnmente visto en 2 bucles for, 3 bucles for y k bucles for.
  • El consumo de algoritmo aumenta con n y el rendimiento es deficiente
  • En el proceso de desarrollo real, no se recomienda utilizar un bucle con un valor K demasiado grande, de lo contrario el código será muy difícil de mantener.
int n = 100
int v = 0;
for(int i = 0; i < n; i++){
    for(int j = 0; j < n; j++){
        v = v + j + i;
    }
}

Análisis de código: v es 990000, i es 100, j es 100. n es 100 y la complejidad del tiempo es O (100 ^ 2). Eso es O (10000).

El O cúbico (n^3), la k-ésima potencia O(n^k) y el cuadrado O(n^2) son similares, excepto por algunos ciclos más.

// 立方型O(n^3)
for(int i =0; i < n; i++){
    for(int j = 0; j < n; j++){
        for(int m = 0; m < n; m++){

        }
    }
}
// K次方型O(n^k)
for(int i = 0; i < n; i++){
    for(int j = 0; j < n; j++){
        for(int m = 0; m<n; m++){
            for(int p = 0; p < n; p++){
                ... // for循环继续嵌套下去,k值不断增大
            }
        }
    }
}

3.2.6 Tipo factorial O(n!)

  • extremadamente poco común
  • El consumo del algoritmo aumenta con el aumento de n y el rendimiento es extremadamente pobre.
void method(n) {
  for(int i = 0; i < n; i++) {
      method(n-1);
  }
}

La complejidad temporal del tipo factorial O(n!) se calcula según el  método de (n!+(n-1)!+(n-2)!+ ··· + 1) ++  .((n-1)!+(n-2)!+ ··· + 1)···


 

Supongo que te gusta

Origin blog.csdn.net/qq_42014561/article/details/129557673
Recomendado
Clasificación