Estructura y algoritmo de datos (Capítulo 2): Análisis de complejidad

1. Análisis de complejidad

En primer lugar, debe quedar claro que la esencia de la estructura y el algoritmo de datos es resolver el problema de "rápido" y "ahorro". Para describir la calidad de un algoritmo, se necesita el análisis de complejidad, que se puede dividir en los dos tipos siguientes.

  • complejidad del tiempo

  • Complejidad espacial

La complejidad del tiempo es la velocidad de describir el algoritmo y la complejidad del espacio es el ahorro de describir el algoritmo. En términos generales, la complejidad es la complejidad del tiempo. Después de todo, el espacio de almacenamiento de las computadoras modernas ya no es tan reducido. La complejidad del tiempo es nuestro contenido clave de investigación.

En segundo lugar, la gran Ocomplejidad de la representación

Primero, mire un fragmento de código, busque la 1~nsuma acumulada.

int demo(int n) {

    int i;
    int sum = 0;

    for(i=1; i<n; i++) {
        sum += i;
    }

    return sum;
}

Ahora estimemos el tiempo de ejecución de este código (los siguientes son ejemplos de complejidad temporal, y la complejidad espacial se discutirá al final).

Desde el CPUpunto de vista, cada línea de código realiza una operación similar para leer datos - operación - escribir datos . Aquí, por conveniencia del cálculo, se asume que el tiempo de ejecución de cada línea de código es el mismo, a trepresenta el tiempo requerido para una línea, nrepresenta la magnitud del tamaño de los datos, T(n)indica el tiempo de ejecución total del código.

Entonces, ¿cuál es el tiempo total de ejecución de este código? Contemos.

Primero, el cuerpo tiene una 5declaración de función , la 1、2、5declaración se ejecuta un total de 3veces, el tiempo requerido es 3*t; la primera 3、4declaración se ejecuta cada nvez, el tiempo requerido es 2*n*t. Agregue el tiempo de ejecución de estos dos segmentos de código y el resultado es el tiempo total requerido para este código.

T (n) = (2 n + 3) t T (n) = (2n + 3) t T ( n )=( 2 n+3 ) t

Se puede obtener una regla mediante la ecuación anterior, T(n)ya que cuanto nmás grande es, se vuelve cada vez más pequeña. Entonces, T(n)con nuna notación matemática proporcional se puede escribir.

T (n) = O (f (n)) T (n) = O (f (n)) T ( n )=O ( f ( n ) )

Cuál f(n)es el tiempo requerido para la ejecución y los segmentos de código, Oindica T(n)la f(n)relación entre el proporcional.

A partir de la fórmula, el tiempo requerido para la ejecución del segmento de código se puede expresar como T (n) = O (2 n + 3) T (n) = O (2n + 3)T ( n )=O ( 2 n+3 ) . Esta es lanotación de complejidad a lograndeO. LaOcomplejidad del tiempograndeno realiza realmente el código específico que indica el tiempo real, sino eltiempo de ejecución del código con el cambio de crecimiento de la escala de datos de tendencia, por lo tanto, también se conoce comocomplejidad progresiva del tiemporeferida a lacomplejidad del tiempo.

En realidad O (2 n + 3) O (2n + 3)O ( 2 n+3 ) No es una representación de la complejidad del tiempo final. En el análisis de complejidad real, generalmente seignoranlasconstantes,coeficientesyórdenes bajos dela fórmula. Debido a que estas tres partes no afectan la tendencia de crecimiento (recuerde que la complejidad del tiempo es en realidad complejidad del tiempo progresiva), solo necesita registrar una magnitud máxima. La representación final de la complejidad del tiempo esO (n) O (n)O ( n )

En tercer lugar, el método de análisis de la complejidad.

1. Pedido máximo

int demo(int n) {

    int i;
    int sum = 0;

    for(i=1; i<n; i++) {
        sum += i;
    }

    return sum;
}

Al analizar la complejidad temporal de un algoritmo o un fragmento de código, céntrese únicamente en el fragmento de código que tiene la mayor cantidad de tiempos de ejecución de bucle.

2. La regla de la suma

int demo(int n) {

    int i;
    int sum = 0;

    for(i=1; i<n; i++) {
        sum += i;
    }
    
    for(i=1; i<n; i++) {
        int j;
        for (j=1; j<n; j++)
            sum += i;
    }

    return sum;
}

Si hay diferentes niveles de complejidad temporal en el código, la complejidad temporal total es igual a la complejidad temporal del código de mayor magnitud.

3. La ley de la multiplicación

int demo(int n) {

    int i;
    int sum = 0;

    for(i=1; i<n; i++) {
        int j;
        for (j=1; j<n; j++)
            sum += i;
    }

    return sum;
}

Si es anidamiento, llamada de función, recursividad, etc., solo necesita multiplicar cada parte.

Cuarto, la magnitud de la complejidad

  • Orden constante: O (1) O (1)O ( 1 )

  • Orden logarítmico: O (log ⁡ n) O (\ log n)O ( lo gn )

  • Orden lineal: O (n) O (n)O ( n )

  • Orden logarítmico lineal: O (n log ⁡ n) O (n \ log n)O ( nlo gn )

  • Orden cuadrado: O (n 2) O (n ^ 2)O ( n2 )

  • Orden cúbico: O (n 3) O (n ^ 3)O ( n3 )

  • kOrden de potencia: O (nk) O (n ^ k)O ( nk )

  • Orden exponencial: O (2 n) O (2 ^ n)O ( 2n )

  • Orden factorial: O (n!) O (n!)Oh ( n ! )

Las diferentes magnitudes mencionadas anteriormente se pueden dividir en dos categorías: magnitud polinómica y magnitud no polinómica . Entre ellos, solo hay dos magnitudes no polinómicas: O (2 n) O (2 ^ n)O ( 2n )yO (n!) O (n!)O ( el n- ! ) , También conocido comoNPproblemasno polinomiales.

En circunstancias normales, nuestra complejidad común es solo O (1) O (1)O ( 1 )O (log ⁡ n) O (\ log n)O ( lo gn )O (n) O (n)O ( n )O (n log ⁡ n) O (n \ log n)O ( nlo gn )O (n 2) O (n ^ 2)O ( n2 ) Paraestos cinco, los métodos de análisis comúnmente usados ​​incluyen el orden máximo, la regla de la suma y la regla de la multiplicación. Mientras se dominen, básicamente no hay un gran problema.

Cinco, complejidad del tiempo

Hemos analizado la complejidad del tiempo, pero todavía hay un pequeño problema, por ejemplo, queremos encontrar un elemento de níndice de longitud de la matriz. Si recorremos en orden, la situación ideal es que el primero es lo que estamos buscando, entonces la complejidad del tiempo es O(1); si el último encuentra los datos que queremos, entonces su complejidad de tiempo es O(n).

Para resolver el mismo orden de diferencia de magnitud en el tiempo, una parte de la complejidad del código aparece en diferentes situaciones, necesitamos refinar aún más la clasificación de la complejidad del tiempo, con el fin de obtener una descripción más precisa y completa de la complejidad del tiempo del código, introducido sobre 4un concepto.

1. Complejidad del tiempo en el mejor de los casos

La complejidad temporal de la ejecución del código en el caso más ideal.

2. Complejidad temporal en el peor de los casos

La complejidad temporal de la ejecución del código en el peor de los casos.

3. Complejidad del tiempo promedio de los casos

Los dos mejores y peores casos anteriores son eventos de pequeña probabilidad, y la complejidad del tiempo promedio del caso es la más representativa de la complejidad del tiempo de un algoritmo. Debido a que la complejidad temporal del caso promedio requiere la introducción de probabilidad para el análisis, también se denomina complejidad temporal promedio ponderada .

4. Complejidad del tiempo amortizado

En circunstancias normales, el código tiene una complejidad de bajo nivel durante la ejecución, y la complejidad de alto nivel aparecerá en casos muy raros. Así es como podemos distribuir uniformemente la complejidad de alto nivel a cada complejidad de bajo nivel. Este análisis utiliza el idea de análisis amortizado .

De hecho, solo necesitamos conocer la complejidad del tiempo. Estos cuatro métodos son todos suplementos para algunos casos especiales de complejidad temporal, y no hay necesidad de dedicar mucho esfuerzo para estudiarlos. Probablemente sepa que existe este tipo de clasificación de complejidad temporal. Si desea aprenderlo usted mismo o Tenga un entrevistador con discapacidad cerebral. Si desea preguntar sobre esto, puede encontrar la información y la investigación por su cuenta, y no lo explicaré aquí.

Seis, complejidad espacial

Como se explicó anteriormente, la complejidad del tiempo es la complejidad del tiempo progresiva, que representa la relación de crecimiento entre el tiempo de ejecución de un algoritmo y la escala de los datos. Entonces, la complejidad espacial es la complejidad espacial progresiva, que representa la relación de crecimiento entre el espacio de almacenamiento del algoritmo y la escala de datos.

Mire un fragmento de código, defina una nueva matriz y recorra la salida después de la asignación.

void demo(int n) {

    int i;
    int data[n];

    for(i=0; i<n; i++) {
        data[i] = i * i;
    }

    for(i=0; i<n; i++) {
        printf("%d\n", data[i]);
    }
}

Con el análisis de complejidad del tiempo, la función del cuerpo de 1la declaración es un orden constante, ignorar; las primeras 2declaraciones aplican un tamaño nde intun tipo de matriz, de modo que todo el espacio de complejidad del código es O (n) O (n)O ( n )

Supongo que te gusta

Origin blog.csdn.net/yilovexing/article/details/107025979
Recomendado
Clasificación