Analice la filosofía de escribir programas de algoritmos utilizando "clasificación por selección", el cálculo de la complejidad del tiempo y el espacio y cómo verificar la exactitud del algoritmo.

Algoritmo de clasificación: clasificación por selección

Evaluación:
La más simple: la más consistente con el pensamiento natural de las personas
La menos útil: básicamente no se utiliza en la práctica de la ingeniería

Complejidad del tiempo: O(n^2)
Complejidad del espacio: O(1)

Contenido de esta sección:
Cómo calcular la complejidad del tiempo y el espacio
Cómo verificar algoritmos: generadores de números aleatorios, logaritmos
La filosofía de escribir programas de algoritmos

Idea de algoritmo de clasificación de selección

Un algoritmo que está más en línea con el pensamiento humano:
cada vez que lo recorre, encuentre el valor más pequeño y colóquelo al frente (intercambie) hasta que se encuentren todos los valores. El orden está ordenado. De pequeño a grande,
¿por qué aquí aparece "intercambio" en lugar de "inserción"? Mi comprensión personal: en la disposición de la memoria, el "intercambio" de elementos de la matriz mueve un área de memoria más pequeña, mientras que la "inserción" requiere más memoria las áreas se mueven

¿Cómo escribir un programa de algoritmo? La filosofía de escribir algoritmos.

  • De lo simple a lo complejo
    • Verificar paso a paso
    • Imprimir múltiples resultados intermedios
  • Primero la parte y luego el todo.
    • Cuando no tengas idea, analízalo primero.
  • Primero duro y luego bien.
    • Cambio de nombre de variable
    • Fusión de declaraciones
    • Procesamiento de límites

Específicamente, ¿cómo escribir el algoritmo de clasificación por selección?

De simple a complejo: primero ignore el bucle de doble capa, escriba solo el bucle más interno y solo haga lo primero: el bucle encuentra el subíndice del valor mínimo en la matriz. Una división más cercana: hay una variable específicamente
Registro el subíndice donde se encuentra el valor mínimo. Primero suponga que el subíndice es 0. Comience a seleccionar desde la posición de 1. Al llegar a un determinado elemento, si la comparación encuentra que hay un valor menor que el valor con el subíndice 0, actualice el valor mínimo. El valor de la variable de subíndice de valor es el nuevo subíndice

Versión aproximada del código:

private static void sort1(int[] arr) {
    
    
    int minPos = 0;
    for (int i = 1; i < arr.length; i++) {
    
    
        if (arr[minPos] > arr[i]) {
    
    
            minPos = i;
        }
    }
    // 此时下标为 minPos 的值就是我们挑选出来的最小值
    System.out.println("minPos = " + minPos);
    System.out.println("arr = " + Arrays.toString(arr));
    // 交换: 将最小值与下标为0的值做交换
    int tmp = arr[0];
    arr[0] = arr[minPos];
    arr[minPos] = tmp;
    // 再次打印
    System.out.println("after arr1 = " + Arrays.toString(arr));

    // 第一轮执行完毕,准备第二轮
    minPos = 1;
    for (int i = 2; i < arr.length; i++) {
    
    
        if (arr[minPos] > arr[i]) {
    
    
            minPos = i;
        }
    }
    // 此时下标为 minPos 的值就是挑选出来的最小值
    System.out.println("minPos = " + minPos);
    System.out.println("arr = " + Arrays.toString(arr));
    // 交换: 将最小值与下标为1的值做交换
    tmp = arr[1];
    arr[1] = arr[minPos];
    arr[minPos] = tmp;
    // 交换后,下标为1的位置就是本轮挑选出来的最小值
    System.out.println("arr2 = " + Arrays.toString(arr));

    // ...
    // 发现规律:每一轮的结果就是挑选出一个最小值,并与指定下标的值交换
    // 待交换的下标是从0开始递增,直到length - 1
}

línea de corriente

Descubra las reglas: El resultado de cada ronda es elegir un valor mínimo e intercambiarlo con el valor del subíndice especificado. El
subíndice a intercambiar comienza desde 0 y aumenta hasta longitud - 1

private static void sort2(int[] arr) {
    
    
    for (int i = 0; i < arr.length - 1; i++) {
    
    
        int minPos = i;
        for (int j = i + 1; j < arr.length; j++) {
    
    
            if (arr[minPos] > arr[j]) {
    
    
                minPos = j;
            }
        }
        System.out.println("第 " + i + " 轮外层循环,找到的最小值下标: " + minPos);
        int tmp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = tmp;
        System.out.println("交换后的数组 = " + Arrays.toString(arr));
    }
    System.out.println("arr = " + Arrays.toString(arr));
}

Calcular la complejidad del tiempo y el espacio.

Primero analice la complejidad del tiempo, luego analice la complejidad del espacio.

Tome el método sort2 como ejemplo para calcular la complejidad del tiempo y el espacio y analice la complejidad del tiempo de cada oración. Para facilitar la expresión, una oración del código Java se expresa como una unidad de complejidad del tiempo.

Análisis de complejidad del tiempo.

private static void sort2(int[] arr) {
    
     // 方法名,不计入复杂度,假设参数重的arr长度为n,以下的代码将以n为基础
    for (int i = 0; // 代码 i=0 只会执行一次,计为1
    		i < arr.length - 1; // 代码 i<arr.length-1 将执行 length-1 次,计为n-1,又因n很大的时候与n-1相差无几,所以可直接计为n
    		i++) {
    
     // 代码 i++ 将执行n次,计为n
        int minPos = i; // 执行 n-1 次,计为 n
        for (int j = i + 1; // 该语句将执行 (n-1) 次,与外层循环的次数一致
        	j < arr.length; // 该语句将执行 (n-1)+(n-2)+(n-3)+...+2+1 次,这是个等差数列,换算一下为: n(n-1)/2 = n^2/2 - n/2
        	j++) {
    
     // 该语句是上句话的次数+1,同理当n很大的时候,与n相关的+1相差无几,所以为了方便计算,+1就不在单独加一,即该语句与上句话的时间复杂度相同
            if (arr[minPos] > arr[j]) {
    
     // 该语句与等差数列的次数相同
                minPos = j; // 同上
            }
        }
        System.out.println("第 " + i + " 轮外层循环,找到的最小值下标: " + minPos); // 该语句是调试打印语句,不计入时间复杂度
        int tmp = arr[i]; 		// 该语句将执行 (n-1) 次
        arr[i] = arr[minPos]; 	// 同上
        arr[minPos] = tmp; 		// 同上
        System.out.println("交换后的数组 = " + Arrays.toString(arr)); 			// 调试打印语句,忽略
    }
    System.out.println("arr = " + Arrays.toString(arr)); 						// 调试打印语句,忽略
}

Del análisis de complejidad temporal de los comentarios del código fuente anterior, la complejidad temporal con mayor potencia es la secuencia aritmética, es decir, la n^2/2 - n/2complejidad temporal de todo el algoritmo solo necesita encontrar la oración con mayor potencia como todo el algoritmo. La complejidad del tiempo es suficiente,
luego simplifique la fórmula compleja, ignore los términos constantes, ignore los términos de baja potencia, solo conserve la potencia más alta, el valor es, es decir, n^2la complejidad temporal de todo el algoritmo es:O(n^2)

Se puede ver que la complejidad temporal de los bucles de dos niveles es n^2. En el futuro, puede buscar directamente bucles multinivel. La complejidad temporal básica de un bucle de nivel básico se eleva a varias potencias.

Análisis de complejidad espacial.

空间复杂度Se refiere al espacio adicional requerido por el algoritmo.
Principio: busque principalmente el espacio relacionado con el tamaño de los datos e ignore las variables de tipo básico individuales, como la variable de índice en el bucle for iy la variable de índice en el bucle interno , y también ignore el algoritmo de selección y clasificación de variables jutilizado para el intercambio. , No se utiliza adicionalmente. Un espacio equivalente al volumen de datos, por lo que la complejidad del espacio es la más básica.int tmp
O(1)

La “inestabilidad” de la clasificación por selección

¿Qué es la inestabilidad? Es decir, hay dos elementos con valores equivalentes en una matriz. Después de la clasificación por selección, los dos elementos se pueden intercambiar. La posición relativa de estos dos elementos es inestable.

Por ejemplo, supongamos que lo siguiente es una matriz que se va a ordenar: agregue un código de impresión de depuración antes de que se produzca el intercambio en
int[] arr = {5, 4, 2, 5, 1, 3};
el método :sort2()
System.out.printf("即将发生交换arr[%s]=%s <-> arr[%s]=%s\n", i, arr[i], minPos, arr[minPos]);

Puede ver el siguiente resultado:

即将发生交换arr[0]=5 <-> arr[4]=1
即将发生交换arr[1]=4 <-> arr[2]=2
即将发生交换arr[2]=4 <-> arr[5]=3
即将发生交换arr[3]=5 <-> arr[5]=4
即将发生交换arr[4]=5 <-> arr[4]=5
arr = [1, 2, 3, 4, 5, 5]

Vemos que la última fila de resultados muestra que los resultados de la clasificación efectivamente están ordenados de pequeño a grande. Este es el orden correcto, pero no te preocupes, mira si el elemento con el valor 5 se intercambia de un lado a otro con el valor con subíndice
0 La ruta de intercambio de 5: [0] -> [4]
La ruta de intercambio del valor 5 cuyo subíndice es 3: [3] -> [5]
Algunas personas dicen que el orden relativo de los dos valores ​​​5 aquí no ha cambiado, el primer 5 se intercambia de la posición 0 a la posición 4, y el segundo 5 se intercambia de la posición 3 a la posición 5. Después del intercambio, aún mantienen el orden relativo.
No se preocupe, el ejemplo anterior fue escrito por mí casualmente y resultó que no llegó a la escena especial de inestabilidad. A continuación, usaremos este ejemplo para cambiar ligeramente el orden de la matriz original para activar la escena inestable. cambie los dos últimos números
. 1 y 3 se intercambian para obtener la siguiente matriz:
int[] arr = {5, 4, 2, 5, 3, 1};
Ejecutamos el algoritmo de ordenación por selección nuevamente para obtener el resultado:

即将发生交换arr[0]=5 <-> arr[5]=1
即将发生交换arr[1]=4 <-> arr[2]=2
即将发生交换arr[2]=4 <-> arr[4]=3
即将发生交换arr[3]=5 <-> arr[4]=4
即将发生交换arr[4]=5 <-> arr[4]=5
arr = [1, 2, 3, 4, 5, 5]

La ruta de intercambio del valor 5 con el índice 0: [0] -> [5]
La ruta de intercambio del valor 5 con el índice 3: [3] -> [4]
En este momento, los primeros 5 se intercambian desde posición 0 En la posición No. 5, el segundo 5 se intercambió de la posición 3 a la posición 4, por lo que las posiciones relativas de los dos 5 cambiaron después de sus respectivos intercambios, y se desencadenó la escena de inestabilidad.

Ejemplos del impacto de la clasificación inestable en el negocio real

Los depositantes del banco están clasificados de mayor a menor en términos de monto de depósito. Sin embargo, hay una gran cantidad de depositantes con montos iguales, por lo que el orden de los depositantes con montos iguales es inestable. Tal vez un determinado evento simplemente envíe regalos a los 1.000 primeros. depositantes más grandes. Debido a la clasificación inestable, la cantidad asignada a la enésima persona es 500 000, y hay 100 depositantes de exactamente 500 000. Si las 100 personas están incluidas en el rango de obsequios, el número total de personas llegará a 1001, pero las reglas comerciales Requiere estrictamente que solo se puedan incluir las primeras 1.000 personas, por lo que debe haber un depositante con un depósito de 500.000 para ser excluido.
El algoritmo de clasificación por selección no puede garantizar que el orden relativo de los depositantes con depósitos de 500.000 antes de la clasificación permanezca sin cambios, lo que constituye la "inestabilidad" del algoritmo de clasificación por selección.

¿Cómo verificar el algoritmo?

Algoritmo de verificación: logaritmizador (un instrumento para comparar matrices)

  1. Observación visual: solo se usa para código de prueba, no para código de ingeniería, porque: es propenso a errores; no se puede ver a simple vista cuando la muestra es grande. Entonces los pasos comienzan desde el punto 2:
  2. Generar suficientes muestras aleatorias
  3. Calcule los resultados de la muestra utilizando el algoritmo correcto
  4. Comparar los resultados de algoritmos verificados.

Generar suficientes muestras aleatorias

Genere una matriz, el número se especifica mediante el parámetro, luego cree un objeto aleatorio y luego genere un entero aleatorio para cada subíndice de la matriz. El valor máximo del entero aleatorio se especifica mediante el parámetro. El código es el siguiente:

private int[] generateRandomArray(int len, int max) {
    
    
    int[] arr = new int[len];
    Random r = new Random();
    for (int i = 0; i < arr.length; i++) {
    
    
        arr[i] = r.nextInt(max);
    }
    return arr;
}

Comparar dos matrices para la igualdad

Si las longitudes no son iguales, las matrices deben ser desiguales. De lo contrario, recorra las dos matrices y extraiga los valores en los subíndices correspondientes de las dos matrices. A modo de comparación, si se encuentra desigual, se devolverá desigual. Si no se encuentra ningún desigual al final del recorrido, entonces el retorno es igual, el código es el siguiente:

private boolean checkArrayEquals(int[] arr1, int[] arr2) {
    
    
    if (arr1.length != arr2.length) {
    
    
        return false;
    }

    for (int i = 0; i < arr1.length; i++) {
    
    
        if (arr1[i] != arr2[i]) {
    
    
            return false;
        }
    }
    return true;
}

Impresión auxiliar de los primeros N elementos de una gran matriz.

Dado que hay demasiados valores en una matriz grande, es inconveniente imprimirlos todos. En un escenario de clasificación, solo verificar si los primeros N elementos están en orden puede reflejar aproximadamente el orden de toda la matriz. El código es como sigue:

private void printFirstN(int[] arr, int n) {
    
    
    System.out.print("first-" + n + ": ");
    for (int i = 0; i < n; i++) {
    
    
        System.out.print(arr[i] + " ");
    }
    System.out.println();
}

Funciones principales del algoritmo de verificación.

Después de completar la función auxiliar anteriormente, puede escribir la función principal. Primero genere aleatoriamente una matriz de 10,000 elementos y luego copie uno para obtener dos copias. Una se usa para ordenar mediante nuestro propio algoritmo de clasificación y la otra se usa para ordenar mediante la función de clasificación estándar. Luego compare los resultados de las dos clasificaciones. algoritmos. El código se muestra a continuación:

public void test_data_checker() {
    
    
    for (int i = 0; i < 10; i++) {
    
    
        int[] arr = generateRandomArray(10000, 10000);
        int[] arr2 = new int[arr.length];
        System.arraycopy(arr, 0, arr2, 0, arr.length);
        printFirstN(arr, 10);
        SelectionSort.sort2(arr);
        Arrays.sort(arr2);
        printFirstN(arr, 10);
        printFirstN(arr2, 10);
        boolean b = checkArrayEquals(arr, arr2);
        if (!b) {
    
    
            throw new RuntimeException("排序结果与标准排序算法不一致");
        }
    }
}

Envuelva la lógica anterior en un bucle y repita varias veces. Si el resultado es diferente al mismo tiempo, se generará un mensaje de excepción.

Supongo que te gusta

Origin blog.csdn.net/booynal/article/details/125590320
Recomendado
Clasificación