[Estructura y algoritmo de datos JS] Implementación del algoritmo de clasificación Hill y clasificación rápida

Prefacio

Se han introducido varios algoritmos de clasificación simples antes. Antes de ingresar formalmente al algoritmo de clasificación avanzado, repasemos la idea principal de la clasificación por inserción: extrayendo un elemento marcado, los datos de la izquierda forman una secuencia ordenada localmente y los datos en el la derecha es ninguna Secuencia ordenada, y luego cada elemento de la secuencia desordenada se inserta en la posición correspondiente de la secuencia ordenada.

texto

revisión

Si existe tal secuencia:
Inserte la descripción de la imagen aquí
cuando el último elemento 1 está dispuesto, tiene la siguiente estructura:
Inserte la descripción de la imagen aquí
luego en la última pasada, necesitamos mover todos los elementos para colocar el elemento 1 en la posición correspondiente,
Inserte la descripción de la imagen aquí
este es el problema. ¿Cómo hacer que avance un poquito sin tener que dar tantos pasos atrás? Luego presentó la clasificación de Hill.

Tipo de colina

La mejora de la clasificación Hill rompe con la complejidad temporal del algoritmo de clasificación anterior, que es O (N 2 ).

pensamiento

La ordenación de Shell es una especie de ordenación por inserción, también conocida como "ordenación incremental decreciente" (ordenación por incremento decreciente), que es una versión más eficiente y mejorada del algoritmo de ordenación por inserción directa.

  • El primer paso es agrupar los valores del subíndice en ciertos incrementos (generalmente N / 2, y luego dividirlos a la mitad sucesivamente) para ordenar cada grupo según el orden de inserción.
  • En el segundo paso, el incremento se reduce gradualmente y cada grupo contiene más y más palabras clave. Cuando el incremento se reduce a 1, todo el archivo se divide en un grupo y el algoritmo finaliza.

ejemplo
Inserte la descripción de la imagen aquí

Elección del incremento correcto
En exploraciones anteriores, existen varias secuencias de incrementos bien conocidas.

  • Secuencia incremental del manuscrito Hill : entre los manuscritos ordenados por Hill, se recomienda que el espaciado inicial sea N / 2 y el espaciado de cada pasada se divide en dos mitades. Por ejemplo, en una matriz de N = 100, la secuencia de espaciado incremental será : 50,25,12,6,3,1
  • Secuencia incremental de Hibbard : el algoritmo incremental es 2 k-1 , que es 1 , 3, 5, 7 ... etc. La peor complejidad es O (N 3/2 ), y se supone que la complejidad promedio es O (N 5/4 ).
  • Secuencia incremental de Sedgewick : El algoritmo incremental es 4 i -32 i + 1, que es 1,5,19,41,109 ... etc.
    La peor complejidad es O (N 4/3 ) y la complejidad promedio es O (N 7/6 ).

La complejidad de la secuencia incremental de Hibbard y la secuencia incremental de Sedgewick aún no se ha confirmado, y también es relativamente difícil de implementar. Por lo tanto, elegimos la secuencia incremental del manuscrito Hill. Este método no requiere trabajo de cálculo adicional antes de comenzar la clasificación.

Implementación del algoritmo de clasificación de colinas

// 希尔排序
ArrayList.prototype.sellSort = function () {
    
    
    // 1.获取数组的长度
    var length = this.array.length;

    // 2.选择希尔排序的原稿增量,初始间距是N / 2
    var gap = Math.floor(length / 2);

    //3.让间隔gap不断的减小
    while (gap >= 1) {
    
    
        // 4.以grp作为间隔,进行分组,分组进行插入排序
        for (var i = gap; i < length; i++) {
    
    
            var temp = this.array[i];
            var j = i;
            while (this.array[j - gap] > temp && j > gap - 1) {
    
    
                this.array[j] = this.array[j - gap];
                j -= gap;
            }

            // 5.将j位置的元素赋值给temp
            this.array[j] = temp;

        }
        // 6.重新计算新的间隔
        gap = Math.floor(gap / 2);
    }
}

Eficiencia de clasificación de colinas

La complejidad del tiempo es O (N 2 )

La clasificación Hill propone un método mejorado basado en las dos propiedades siguientes de la clasificación por inserción:

  • La clasificación por inserción tiene una alta eficiencia cuando se opera con datos que casi se han clasificado, es decir, puede lograr la eficiencia de la clasificación lineal.
  • Pero la ordenación por inserción es generalmente ineficaz, porque la ordenación por inserción solo puede mover los datos un bit a la vez.

Ordenación rápida

El ordenamiento Hill mencionado anteriormente es una mejora del ordenamiento por inserción, mientras que el ordenamiento rápido es una versión mejorada del ordenamiento por burbujas. De hecho, es mucho mejor que el ordenamiento por burbujas. Utiliza recursividad.

pensamiento

  • El primer paso: determinar un punto de referencia ;
  • Paso 2: Coloque todos los números más pequeños que la línea de base antes de la línea de base, y todos los números más grandes que la línea de base después de la línea de base (los mismos números se pueden colocar en cualquier lado). Después de esta partición, la referencia se ubica en el medio de la secuencia, este proceso se denomina operación de partición.
  • Realice de forma recursiva los pasos primero y segundo en la parte delantera y trasera del punto de referencia hasta que se complete la clasificación.

Elija el punto de referencia adecuado

    1. Los últimos datos de la secuencia parcial se seleccionan como referencia, y luego se utilizan dos punteros móviles.Si el número del puntero frontal es mayor que el número del puntero trasero, se intercambian. (La operación es simple, pero no representativa)
    1. Se utiliza un índice aleatorio como punto de referencia en el rango de datos , y el punto de referencia se coloca al final de la secuencia parcial, y la operación es la misma que en el primer método. (La probabilidad es igual, pero es necesario implementar números aleatorios, sin operación unificada)
    1. Seleccione el primer, el medio y los últimos tres datos de la secuencia parcial para ordenar la mediana y use la mediana como punto de referencia para colocar la penúltima posición en la secuencia. (Operación representativa, unificada)

Consideración integral, finalmente elegimos el método de tomar la mediana
Inserte la descripción de la imagen aquí

Algoritmo de clasificación rápida para lograr
2, intercambiar dos números

// 交换两个数
ArrayList.prototype.swap = function (a, b) {
    
    
    var temp = this.array[a];
    this.array[a] = this.array[b];
    this.array[b] = temp;
}

1. Determine el punto de referencia

// 确定基准
ArrayList.prototype.median = function (left, right) {
    
    
    // 1.求出中间的位置
    var mid = Math.floor((left + right) / 2);
    // 2.判断并且进行交换 三数的冒泡思想
    if (this.array[left] > this.array[mid]) this.swap(left, mid);
    if (this.array[left] > this.array[right]) this.swap(left, right);
    if (this.array[mid] > this.array[right]) this.swap(mid, right);
    // 3.巧妙的操作: 将mid移动到right - 1的位置.
    this.swap(mid, right - 1);
    // 4.返回pivot
    return this.array[right - 1];
}
// 快速排序
ArrayList.prototype.quickSort = function () {
    
    
    this.quick(0, this.array.length - 1);
}

// 内部递归使用
ArrayList.prototype.quick = function (left, right) {
    
    

    // 1.递归结束条件
    if (left >= right) return false;
    // 2.获取基准
    var pivot = this.median(left, right);

    // 3.定义变量,开始进行交换
    var i = left;
    var j = right - 1;
    while (i < j) {
    
    
        // 3.1 找到比基准值大的数停止
        while (i < right && this.array[++i] < pivot) {
    
     }
        // 3.2 找到比基准值小的数停止
        while (j > left && this.array[--j] > pivot) {
    
     }
        // 3.3 交换与否
        if (i < j) {
    
    
            this.swap(i, j);
        } else {
    
    
            break;
        }
    }
    // 4.将基准放在正确的位置
    this.swap(i, right - 1);
    // 5.递归的调用左边序列
    this.quick(left, i - 1);
    // 6.递归的调用右边序列
    this.quick(i + 1, right);
}

Edición Lite de la Enciclopedia Baidu

const quickSort = (array) => {
    
    
    const sort = (arr, left = 0, right = arr.length - 1) => {
    
    
        if (left >= right) {
    
    //如果左边的索引大于等于右边的索引说明整理完毕
            return
        }
        let i = left
        let j = right
        const baseVal = arr[j] // 取无序数组最后一个数为基准值
        while (i < j) {
    
    //把所有比基准值小的数放在左边大的数放在右边
            while (i < j && arr[i] <= baseVal) {
    
     //找到一个比基准值大的数交换
                i++
            }
            arr[j] = arr[i] // 将较大的值放在右边如果没有比基准值大的数就是将自己赋值给自己(i 等于 j)
            while (j > i && arr[j] >= baseVal) {
    
     //找到一个比基准值小的数交换
                j--
            }
            arr[i] = arr[j] // 将较小的值放在左边如果没有找到比基准值小的数就是将自己赋值给自己(i 等于 j)
        }
        arr[j] = baseVal // 将基准值放至中央位置完成一次循环(这时候 j 等于 i )
        sort(arr, left, j - 1) // 将左边的无序数组重复上面的操作
        sort(arr, j + 1, right) // 将右边的无序数组重复上面的操作
    }
    const newArr = array.concat() // 为了保证这个函数是纯函数拷贝一次数组
    sort(newArr)
    return newArr
}

Eficiencia de clasificación de colinas

La complejidad del tiempo es O (N * logN)

para resumir

Solo aprendí estos dos algoritmos de clasificación más rápidos. Todavía no he aprendido la clasificación de cubos y la clasificación por combinación. Los compartiré cuando los haya aprendido. Vamos juntos ヾ (◍ ° ∇ ° ◍) ノ ゙.

Supongo que te gusta

Origin blog.csdn.net/weixin_42339197/article/details/102950030
Recomendado
Clasificación