Artigo Diretório
Prefácio
Vários algoritmos de classificação simples foram introduzidos antes. Antes de entrarmos formalmente no algoritmo de classificação avançada, vamos revisar a ideia principal da classificação por inserção: extrair um elemento marcado, os dados à esquerda formam uma sequência ordenada localmente e os dados no à direita é nenhum. Sequência ordenada, e então cada elemento da sequência desordenada é inserido na posição correspondente da sequência ordenada.
texto
Reveja
Se existe essa sequência:
quando o último elemento 1 é organizado, ele tem a seguinte estrutura:
então, na última passagem, precisamos mover todos os elementos para colocar o elemento 1 na posição correspondente.Este
é o problema. Como fazer 1 avançar um pouco sem ter que dar tantos passos para trás? Em seguida, introduziu a classificação Hill.
Tipo de colina
O aprimoramento da classificação de Hill rompe a complexidade do tempo do algoritmo de classificação anterior, que é O (N 2 ).
pensei
A classificação de Shell é um tipo de classificação por inserção, também conhecida como "classificação incremental decrescente" (Diminishing Increment Sort), que é uma versão mais eficiente e aprimorada do algoritmo de classificação por inserção direta.
- A primeira etapa é agrupar os valores subscritos em certos incrementos (geralmente N / 2 e dividir pela metade sucessivamente depois) para classificar cada grupo de acordo com a classificação de inserção.
- Na segunda etapa, o incremento é reduzido gradualmente, e cada grupo contém mais e mais palavras-chave.Quando o incremento é reduzido para 1, todo o arquivo é dividido em um grupo e o algoritmo é encerrado.
exemplo
Escolhendo o incremento correto
Em explorações anteriores, existem várias sequências de incremento bem conhecidas.
- Sequência incremental do manuscrito de Hill : entre os manuscritos classificados por Hill, o espaçamento inicial é recomendado como N / 2 e o espaçamento de cada passagem é dividido em duas metades. Por exemplo, em uma matriz de N = 100, a sequência de espaçamento incremental será : 50,25,12,6,3,1
- Sequência incremental de Hibbard : o algoritmo incremental é 2 k-1 , que é 1 , 3, 5, 7 ... etc. A pior complexidade é O (N 3/2 ), e a complexidade média é estimada como O (N 5/4 ).
- Sequência incremental de Sedgewick : O algoritmo incremental é 4 i -32 i + 1, que é 1,5,19,41,109 ... etc.
A pior complexidade é O (N 4/3 ), e a complexidade média é O (N 7/6 ).
A complexidade da sequência incremental de Hibbard e da sequência incremental de Sedgewick ainda não foi confirmada, e também é relativamente difícil de implementar. Portanto, escolhemos a sequência incremental do manuscrito de Hill. Este método não requer trabalho de cálculo adicional antes de iniciar a classificação.
Implementação do algoritmo de classificação de Hill
// 希尔排序
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);
}
}
Eficiência de classificação em colinas
A complexidade do tempo é O (N 2 )
A classificação de Hill propõe um método aprimorado com base nas duas propriedades a seguir de classificação por inserção:
- A classificação por inserção tem alta eficiência ao operar em dados que quase foram classificados, ou seja, pode atingir a eficiência da classificação linear.
- Mas a classificação por inserção geralmente é ineficiente, porque a classificação por inserção só pode mover os dados um bit por vez.
Ordenação rápida
A classificação Hill mencionada anteriormente é uma melhoria da classificação por inserção, enquanto a classificação rápida é uma versão atualizada da classificação por bolha. Na verdade, é muito melhor do que a classificação por bolha. Ele usa recursão.
pensei
- A primeira etapa: determinar um benchmark ;
- Etapa 2: coloque todos os números menores que a linha de base antes da linha de base e todos os números maiores que a linha de base depois da linha de base (os mesmos números podem ser colocados em qualquer um dos lados). Após esta partição, a referência está localizada no meio da seqüência.Este processo é chamado de operação de partição.
- Execute recursivamente a primeira e a segunda etapas na frente e atrás do benchmark até que a classificação seja concluída.
Escolha o benchmark certo
-
- Os últimos dados da sequência parcial são selecionados como referência e, em seguida, dois ponteiros móveis são usados.Se o número do ponteiro frontal for maior que o número do ponteiro traseiro, eles serão trocados. (A operação é simples, mas não representativa)
-
- Um índice aleatório é usado como referência na faixa de dados , e a referência é colocada no final da sequência parcial, e a operação é a mesma do primeiro método. (A probabilidade é igual, mas números aleatórios precisam ser implementados, nenhuma operação unificada)
-
- Selecione o primeiro, o meio e os últimos três dados da sequência parcial para classificar a mediana e use a mediana como referência para colocar a penúltima posição na sequência. (Representante, operação unificada)
Consideração abrangente, finalmente escolhemos o método de tomar a mediana
Algoritmo de classificação rápida para obter
2, troque dois 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 o benchmark
// 确定基准
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);
}
Baidu Encyclopedia Lite Edition
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
}
Eficiência de classificação em colinas
A complexidade do tempo é O (N * logN)
Resumindo
Aprendi apenas esses dois algoritmos de classificação mais rápidos. Não aprendi a classificação de bucket e a classificação de mesclagem ainda. Vou compartilhá-los quando os tiver aprendido. Venham juntos ヾ (◍ ° ∇ ° ◍) ノ ゙.