Cuatro métodos de clasificación comunes (implementados en Java)

Tipo de inserción

Principio de clasificación:
1. Divida todos los elementos en dos grupos , clasificados y sin clasificar;
2. Busque el primer elemento en el grupo sin clasificar e insértelo en el grupo ordenado;
3. Se ha realizado un recorrido de retroceso Los elementos ordenados se comparan con los elementos a insertar a su vez, hasta que se encuentra que un elemento es menor o igual al elemento a insertar, luego el elemento a insertar se coloca en esta posición y los demás elementos se mueven un bit hacia atrás;
El principio es el siguiente:
Inserte la descripción de la imagen aquí
La primera operación: el puntero apunta al segundo elemento y lo compara con el elemento anterior.
Si se cumplen las condiciones, se realiza el intercambio y el puntero se mueve hacia adelante un bit, y los pasos anteriores se repiten hasta que el puntero alcanza el encabezado de la matriz, de lo
contrario significa que ya hay Secuencia, salir del bucle actual;
segunda operación: el puntero apunta al tercer elemento, compararlo con el elemento anterior ...
Inserte la descripción de la imagen aquí

/**
 * @author 悠一木碧
 * 插入排序类
 */
public class Insert {
    
    
    /**
     * 升序排序
     * @param a
     */
    public static void sort(Comparable[] a) {
    
    
        if (null == a) {
    
    
            throw new NullPointerException("空指针数组!");
        }
        int len = a.length;
//        1. 从第二个元素开始进行排序
//        2. 用temp记录当前索引位置, 索引必须 > 0(当索引为0的时候不需要再往前比较了)
//        3.如果满足条件, 则进行交换, 同时将索引前移一位----temp--        
        for (int i = 1; i < a.length; i++) {
    
    
            int temp = i;
            while (temp > 0 && bigger(a[temp - 1], a[temp])) {
    
    
                exchange(a, temp - 1, temp);
                temp--;
            }
        }
    }

    /**
     * 判断a 是否大于 b
     * @param a
     * @param b
     * @return
     */
    private static boolean bigger(Comparable a, Comparable b) {
    
    
        return a.compareTo(b) > 0;
    }

    /**
     * 交换索引index1, index2位置的元素
     * @param a
     * @param index1
     * @param index2
     */
    private static void exchange(Comparable[] a, int index1, int index2) {
    
    
        Comparable comparable = a[index1];
        a[index1] = a[index2];
        a[index2] = comparable;
    }
}

De acuerdo con la regla de derivación de Big O, la complejidad temporal de la clasificación de inserción final es O (N ^ 2) si se retiene el término de mayor orden en la función.

Tipo de colina

La clasificación Hill es una especie de clasificación por inserción, también conocida como " clasificación incremental reducida ", que es una versión más eficiente y mejorada del algoritmo de clasificación por inserción.
En la clasificación de inserción anterior, comparamos una y otra vez, e intercambiamos elementos una y otra vez. Por
ejemplo, para poner 1 en la imagen donde es 3, necesitamos comparar dos veces e intercambiar dos veces.
Inserte la descripción de la imagen aquí

La clasificación Hill se utiliza para optimizar, comparar e intercambiar directamente

Principio de clasificación:
1. Seleccione un incremento y agrupe los datos de acuerdo con el incremento como base para la agrupación de datos;
2. Inserte y ordene cada grupo de datos en el grupo;
3. Reduzca el incremento al más pequeño Reducir a 1, repetir el segundo paso.
En cuanto a la determinación del monto del aumento:
utilizamos

        int len = a.length;
        int increment = 1;
        while (increment < len / 2) {
    
    
            increment = increment * 2 + 1;
        }

Asegúrese de que todos los incrementos sean números impares e incremento> len / 2, es decir, el valor inicial del incremento sea más de la mitad de la longitud de la matriz

Después de determinar el valor inicial del incremento, otra cosa que debe determinarse es el modo de cambio del incremento. La
tendencia de cambio del incremento: grande ----> pequeño ---------- incremento final = 1
El código se puede escribir así:

//      确保increment >= 1
        while (increment > 0) {
    
    
        	...
        	...
        	...
        	increment = increment / 2;
        }

Ahora, para un análisis en profundidad de las similitudes entre la clasificación de Hill y la clasificación de inserción, y las diferentes
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
implementaciones de código:

/**
 * @author 悠一木碧
 * 希尔排序类
 */
public class Shell {
    
    
    /**
     * 对数组内元素进行排序(升序)
     * @param a
     */
    public static void sort(Comparable[] a) {
    
    
        if(null == a){
    
    
            throw new NullPointerException("空指针数组!");
        }
//        1.通过数组的长度确定增长量initialIncrement的初始值, 初始化值为1, 通过循环条件(<len / 2)进行确定
//        2.确定初始值后, 确定循环条件, 由于increment需要逐渐减小, 变换方法为increment /= 2
//        3.初始下标为0 + increment, 1+increment, 2+increment.....区间[increment, len-1]内
//        4.数与数之间的间隔为increment, 从当前的数开始, 与前一个数进行比较(假设前面的数成有序列)
//        5.如果不符合期待的大小关系, 则进行交换, 否则退出循环(说明已经成有序列了)
        int len = a.length;
        int increment = 1;
        while (increment < len / 2) {
    
    
            increment = increment * 2 + 1;
        }
        while (increment > 0) {
    
    
            for (int i = increment; i < len; i++) {
    
    
                int temp = i;
                while(temp >= increment && greater(a[temp - increment], a[temp])){
    
    
                    exchange(a, temp - increment, temp);
                    temp -= increment;
                }

            }
            increment /= 2;
        }
    }

    /**
     * 判断x是否大于y
     *
     * @param x
     * @param y
     * @return
     */
    private static boolean greater(Comparable x, Comparable y) {
    
    
        return x.compareTo(y) > 0;
    }

    /**
     * 交换a数组中, i,j索引处的值
     *
     * @param a
     * @param i
     * @param j
     */
    private static void exchange(Comparable[] a, int i, int j) {
    
    
        Comparable temp = a[i];
        a[i] = a[j];
        a[j] = temp;

    }


}

Nota:
En la clasificación de Hill, no hay una regla fija para el aumento h. Hay muchos artículos que han estudiado varias secuencias crecientes, pero ninguno de ellos puede probar que una determinada secuencia es la mejor.

Combinar ordenación (como ordenación rápida, aplicar la idea de agrupación y adoptar una estrategia recursiva)

Para agregar:
Implementación del código:

/**
 * @author 悠一木碧
 * 归并排序
 */
public class Merge {
    
    
//     辅助数组
    private static Comparable[] assitArray;
    /**
     * 对数组内的元素进行排序
     * @param array
     */
    public static void sort(Comparable[] array){
    
    
        if(null == array){
    
    
            throw new NullPointerException("空指针数组!");
        }
        int len = array.length;
        assitArray = new Comparable[len];
        sort(array, 0, len-1);
    }

    /**
     * 对区间[staIndex, endIndex]中的数组元素进行排序
     * 递归至 staIndex == endIndex停止
     * 在staIndex = endIndex - 1的时候开始调用merge进行归并
     * @param array
     * @param staIndex
     * @param endIndex
     */
    private static void sort(Comparable[] array, int staIndex, int endIndex){
    
    
        if(staIndex < endIndex){
    
    
            int mid = (staIndex + endIndex) / 2;
            sort(array, staIndex, mid);
            sort(array, mid + 1, endIndex);
            merge(array, staIndex, mid, endIndex);
        }
    }

    /**
     * [left, mid], [mid + 1, right]两个子组进行有序组合
     * 1. 定义辅助数组的初始指针, 定义原数组的两个区间的初始指针
     * 2. 依次移动两个区间的指针, 比较他们指向元素的大小, 按大小放入至辅助数组中
     * 3. 将排好序的辅助数组中的元素复制到原数组中
     * 两个区间的指针必定会有一个提前走完, 剩下没走完的指针, 将其剩余的元素放到辅助数组中即可
     * @param left
     * @param mid
     * @param right
     */
    private static void merge(Comparable[] array, int left, int mid, int right){
    
    
        int i = left;
        int index1 = left;
        int index2 = mid + 1;
        while(index1 <= mid && right >= index2){
    
    
            if(bigger(array[index1], array[index2])){
    
    
                assitArray[i++] = array[index2++];
            } else{
    
    
                assitArray[i++] = array[index1++];
            }
        }
        while(index1 <= mid){
    
    
            assitArray[i++] = array[index1++];
        }
        while(index2 <= right){
    
    
            assitArray[i++] = array[index2++];
        }
        if (right - left + 1 >= 0)
            System.arraycopy(assitArray, left, array, left, right + 1 - left);
    }

    /**
     * 判断a > b
     * @param a
     * @param b
     * @return
     */
    private static boolean bigger(Comparable a, Comparable b){
    
    
        return a.compareTo(b) > 0;
    }

    /**
     * 元素a[index1] 和 元素a[index2]进行交换
     * @param a
     * @param index1
     * @param index2
     */
    private static void exchange(Comparable[] a, int index1, int index2){
    
    
        Comparable comparable = a[index1];
        a[index1] = a[index2];
        a[index2] = comparable;
    }
}

Clasificación rápida (recursiva, doble puntero)

Para agregar:
Implementación del código:

/**
 * @author 悠一木碧
 * 快速排序
 */
public class Quick {
    
    
    public static void sort(Comparable[] a) {
    
    
        if(null == a){
    
    
            throw new NullPointerException("传入数组参数为空!");
        }
        int len = a.length;
        if(0 != len){
    
    
            sort(a, 0, len - 1);
        }
    }

    /**
     * 对区间[staIndex, endIndex]中的数组元素进行排序
     * 将其拆分为[lowerLimit, demarcationIndex-1], [demarcationIndex+1, upperLimit]两个区间排序
     * 递归至 staIndex == endIndex停止--------分成只有一个元素的时候停止
     * @param array
     * @param lowerLimit
     * @param upperLimit
     */
    private static void sort(Comparable[] array, int lowerLimit,  int upperLimit){
    
    
        if(lowerLimit >= upperLimit){
    
    
            return;
        }
        int demarcationIndex = grouping(array, lowerLimit, upperLimit);
        sort(array, lowerLimit, demarcationIndex - 1);
        sort(array, demarcationIndex + 1, upperLimit);
    }

    /**
     * 对索引在区间[lowerLimit, upperLimit]内的数组元素进行切分, 并返回切分后分界元素的索引
     * 这里是将左边第一个元素作为分界元素, 所以先让右边的指针先动
     * @param array
     * @param lowerLimit
     * @param upperLimit
     * @return 返回的是变换后的索引
     */
    private static int grouping(Comparable[] array, int lowerLimit, int upperLimit){
    
    
//      1. 定义两个指针, 分别指向待切区间的最小索引 和 最大索引的下一个位置
        int left = lowerLimit;
        int right = upperLimit + 1;
        while (true) {
    
    
//          2. 先移动右指针, 自右向左扫描, 直到找到比分界元素小的元素停止
//          3. 然后移动左指针, 自坐向右扫描, 直到找到比分界元素大的元素停止

            while(less(array[lowerLimit], array[--right])){
    
    
                if(left == right){
    
    
                    break;
                }
            }
//          5. 两个指针重合的时候, 交换分界元素和指针当前指向的元素并返回索引
            if(left == right){
    
    
                exchange(array, lowerLimit, right);
                return right;
            }
            while(less(array[++left], array[lowerLimit])){
    
    
                if(left == right){
    
    
                    break;
                }
            }
//          4. 交换左右指针指向的元素
            if(left == right){
    
    
                exchange(array, lowerLimit, right);
                return right;
            } else{
    
    
                exchange(array, left, right);
            }

        }
    }
    /**
     * 判断x是否小于y
     * @param x
     * @param y
     * @return
     */
    private static boolean less(Comparable x, Comparable y) {
    
    
        return x.compareTo(y) < 0;
    }

    /**
     * 交换a数组中, i,j索引处的值
     * @param a
     * @param i
     * @param j
     */
    private static void exchange(Comparable[] a, int i, int j) {
    
    
        Comparable temp = a[i];
        a[i] = a[j];
        a[j] = temp;

    }
}

Supongo que te gusta

Origin blog.csdn.net/Valishment/article/details/107749862
Recomendado
Clasificación