[Estructura de datos] Análisis e implementación de los diez algoritmos de clasificación principales

Algoritmo de clasificación

Los algoritmos de clasificación se pueden dividir en clasificación interna y clasificación externa. La clasificación interna se realiza en la memoria y no requiere espacio adicional; también se puede dividir en clasificación comparativa y clasificación no comparativa. La siguiente figura es una comparación de rendimiento de diez algoritmos de clasificación comunes. La estabilidad se basa en si la clasificación cambia las posiciones relativas de los elementos originales.

1. Clasificación de burbujas

La ordenación de burbujas utiliza comparaciones por pares de elementos adyacentes y, si el orden es incorrecto, intercambia su orden, de modo que en una ronda, el elemento más grande o el más pequeño se intercambiará en la parte superior. Dado que la forma es muy similar a burbujear una y otra vez, lo llamamos tipo de burbuja. A continuación se muestra el caso de clasificación de pequeño a grande:

/**
     * 冒泡排序:优化:如果一趟排序中没有发生冒泡,说明数组已经有序即可退出循环
     * @param arr
     */
    public static int[] bubbleSort(int[] arr) {
    
    
        boolean flag = false;
        for (int i = 0; i < arr.length - 1; i++) {
    
    
            //每冒泡一次,最大的都会冒泡到最顶端
            for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
                if (arr[j] > arr[j + 1]) {
    
    
                    flag = true;
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
           //优化代码
            if (!flag) {
    
    
                break;
            } else {
    
    
                System.out.println("第" + (i + 1) + "次冒泡" + Arrays.toString(arr));
                flag = false;
            }
        }
        return arr;
    }

2, clasificación de selección

Es decir, en cada ronda de comparación, se selecciona el elemento actual como el valor máximo posible de la ronda, y si el tamaño es incorrecto, se actualiza e intercambia el valor máximo. De esta manera, la posición de un número se puede determinar en cada ronda.

/**
     * 选择排序
     * @param arr
     * @return
     */
    public static int[] selectSort(int[] arr) {
    
    
        for (int i = 0; i < arr.length - 1; i++) {
    
    
            int min = arr[i]; //选择一个作为最小值
            for (int j = i + 1; j < arr.length; j++) {
    
    
                if (arr[j] < min) {
    
    
                   arr[j] = arr[j] + arr[i];
                    arr[i] = arr[j] - arr[i];
                    arr[j] = arr[j] - arr[i];
                }
                min = arr[i];
            }
        }
        return arr;
    }

3. Clasificación por inserción

Comenzando desde el segundo elemento, compare con el primer elemento uno por uno, si corresponde, inserte el elemento en la primera posición; encuentre el elemento apropiado a su vez e insértelo en la segunda y tercera posición. .

Similar a la forma de insertar naipes: comenzando desde la segunda carta, compare con las cartas en la primera posición por turno, y el orden es apropiado, es decir, inserte el elemento en la primera posición y no compare el elemento. es equivalente a retroceder.

Durante la comparación, los elementos delanteros están ordenados y los elementos traseros están desordenados.

/**
     * 插入排序
     * @param arr
     * @return
     */
    public static int[] insertSort(int[] arr) {
    
    
        for (int i = 1; i < arr.length; i++) {
    
    
            //当前需要插入的元素
            int current = arr[i];
            //被插入的位置,即当前数的前一个
            int preIndex = i - 1;
            while (preIndex >= 0 && current < arr[preIndex]) {
    
    
                //被插入位置的元素后移
                arr[preIndex +1] = arr[preIndex];
                //索引向前移动
                preIndex--;
            }
            //当前值插入的位置
            arr[preIndex + 1] = current;
        }
        return arr;
    }

4, clasificación de la colina

Hill sort es una mejora de la ordenación por inserción simple original, también conocida como ordenación incremental de reducción. Por ejemplo, para una secuencia ya ordenada, al insertar, puede ser innecesario realizar múltiples movimientos, lo que afecta la eficiencia.

Idea: Divida la secuencia en grupos de acuerdo con una cierta brecha incremental (generalmente longitud/2) y realice una clasificación de inserción simple en cada grupo de datos; luego continúe agrupando de acuerdo con el método de brecha/=2 y repita el método anterior . Hasta que gap = 1, es decir, cuando se deja un grupo, se ha logrado el efecto de la clasificación de Hill. En este momento, la secuencia está mayormente ordenada y luego se puede realizar una clasificación simple.

El propósito de agrupar es hacer que el grupo esté ordenado y que el conjunto esté lo más ordenado posible.

Reflexión: ¿Por qué la agrupación es adecuada para la clasificación por inserción? Puede ver que la agrupación aquí no es una dicotomía simple, sino que se divide de acuerdo con el espaciado. En la clasificación por inserción anterior, las dos posiciones se intercambian y los elementos en la posición se moverá el espacio Clasificación de acuerdo con la agrupación, solo una vez Simplemente mueva la distancia.

  /**
     * 希尔排序
     *
     * @param arr
     * @return
     */
    public static int[] shellSort(int[] arr) {
    
    
        //控制每次的步长
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
            //按照步长分组
            for (int i = gap; i < arr.length; i++) {
    
    
                //对每次分组的元素进行比较
                int preIndex = i - gap; //组内的前一个元素位置
                int current = arr[i];   //当前值
                //比较组内的所以元素,并移动位置
                while (preIndex >= 0 && arr[preIndex] > current) {
    
     
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                //退出循环后,位置找到插入
                arr[preIndex + gap] = current;
            }
        }
        return arr;
    }

5. Clasificación rápida

El principio de clasificación rápida: encuentre un elemento como valor de referencia (generalmente seleccione el primer elemento), coloque los elementos más pequeños a la derecha y coloque los elementos más grandes a la izquierda . Luego realice esto recursivamente en las secuencias izquierda y derecha hasta que quede un elemento en cada secuencia izquierda y derecha, momento en el cual la secuencia completa está en orden.

Idea: Divida la secuencia en partes relativamente ordenadas izquierda y derecha según el valor de referencia, hasta que cada secuencia tenga 1 longitud.

Práctica : En cada agrupación, compare el valor de referencia con el último elemento, de atrás hacia adelante, hasta encontrar un elemento más pequeño que el valor de referencia, e intercambie posiciones; luego, de adelante hacia atrás, hasta encontrar un elemento más grande que el valor de referencia. elementos encontrados, intercambiar posiciones. Hasta que cambien las posiciones relativas de los índices delantero y trasero, indicando que ha terminado una ronda, se puede determinar una secuencia de valores de referencia en este momento. Luego realice una ordenación rápida en cada secuencia izquierda y derecha por turno.

 /**
     * 交换数组内的两个元素
     * @param a
     * @param n
     * @param m
     */
    private void swap(int[] arr, int a, int b) {
    
    
//        异或交换,可能存在相等时的零值情况
        if(a==b){
    
    
            return;
        }else{
    
    
            arr[a] = arr[a] ^ arr[b];
            arr[b] = arr[a] ^ arr[b];
            arr[a] = arr[a] ^ arr[b];
        }
    }

    /**
     * 快速排序
     * @param arr
     * @param start 起始位置
     * @param end 终点位置
     * @return
     */
    public static void quickSort(int[] arr,int start,int end){
    
    
        //标记索引,记录当前位置
        int low = start;
        int high = end;
        int key = arr[low]; //基准值一般选择序列第一个元素
        while(start<end){
    
    
            //从后往前遍历,直到找到较小值
            while(start<end && arr[end]>=key){
    
    
                end--;
            }
            //退出时如果找到,即交换位置
            if(arr[end]<=key){
    
    
                swap(arr,start,end);
            }
            //从前往后遍历,直到找到较大值
            while(start<end && arr[start]<=key){
    
    
                start++;
            }
            if(arr[start]>=key){
    
    
                swap(arr,start,end);
            }
        }
        //一遍排序结束,基准值位置就确定了,即左边均小于它,右边均大于它
      
        //如果当前起始位置大于标记,说明左边序列仍有元素,对左序列递归进行快速排序
        if(start>low){
    
    
            quickSort(arr,low,start-1);
        }
        //如果当前终点位置小于标记,说明右边序列仍有元素,对右序列递归进行快速排序
        if(end<high){
    
    
            quickSort(arr,end+1,high);
        }
    }

6. Ordenar por fusión

De acuerdo con la idea del método divide y vencerás, divide : divide la secuencia en dos secuencias, y fusiona y ordena respectivamente hasta que la longitud de la subsecuencia sea 1; regla : fusiona cada subsecuencia, aquí se agrega una secuencia adicional para almacenar la resultado combinado. Regla de combinación: compare desde la posición inicial de la secuencia, la más pequeña se completa en el conjunto de resultados; si se recorre una secuencia, otra secuencia se completa directamente en el conjunto de resultados.

/**
     * 归并排序:分治思想,先分再治
     * @param arr
     * @return
     */
    public static int[] mergeSort(int[] arr) {
    
    
        //“分”结束的条件
        if (arr.length < 2) {
    
    
            return arr;
        }
        int mid = arr.length / 2;
        //均分成两个数组序列
        int[] left = Arrays.copyOfRange(arr, 0, mid);
        int[] right = Arrays.copyOfRange(arr, mid, arr.length);
        return merge(mergeSort(left), mergeSort(right));
    }

    /**
     * “治”:将"分"好的数组序列组合起来
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
    
    
        //返回拼装好的结果数组
        int[] result = new int[left.length + right.length];
        //i,j,分别为左右序列的索引,index为结果集的索引
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
    
    
            if (i >= left.length) //当序列的索引超过其长度时说明序列已经排完,只需将另一序加入结果集中即可
                result[index] = right[j++];
            else if (j >= right.length)
                result[index] = left[i++];
            else if (left[i] > right[j]) //左右序列的数据依次进行比较,小的加入到结果集中
                result[index] = right[j++];
            else
                result[index] = left[i++];
        }
        return result;
    }

Resumir:

Como el nombre sugiere:

Ordenación de burbujas: los elementos en posiciones adyacentes se comparan e intercambian, y el mayor valor se intercambiará con la parte superior para formar una burbuja;

Clasificación de selección: dos rondas de, seleccione un valor objetivo en cada ronda, compare e intercambie;

Clasificación por inserción: Seleccione los elementos apropiados desde la primera posición para insertar e intercambiar, y se ordena el frente de la secuencia;

Hill sort: clasificación por inserción para agrupar, clasificación por inserción dentro de cada secuencia;

Clasificación por combinación: divida la secuencia en partes iguales para hacer que la secuencia esté ordenada internamente; luego combine para hacer que la secuencia esté ordenada en general.

Clasificación rápida: divide la secuencia en dos partes que se ordenan en relación con la izquierda y la derecha en función del valor de referencia, hasta que cada secuencia tenga una longitud de 1.

Supongo que te gusta

Origin blog.csdn.net/qq_40589204/article/details/121523972
Recomendado
Clasificación