Java implementa algoritmos de classificação comumente usados (quick sort, merge sort, radix sort)

Algoritmos de Ordenação Comuns

insira a descrição da imagem aqui

ordenação rápida

1. Introdução

Quicksort é um algoritmo de ordenação desenvolvido por Tony Hall. Em média, classificar n itens requer O(nlogn) comparações. No pior caso, comparações Ο(n2) são necessárias, mas isso não é comum. Na verdade, o quicksort geralmente é significativamente mais rápido do que outros algoritmos Ο(nlogn) porque seu loop interno pode ser implementado de forma eficiente na maioria das arquiteturas.

O Quicksort usa uma estratégia de dividir e conquistar para dividir uma lista em duas sublistas.

A classificação rápida é outra aplicação típica da ideia de dividir e conquistar em algoritmos de classificação. Em essência, a ordenação rápida deve ser considerada como um método recursivo de dividir e conquistar baseado na ordenação por bolhas.

O nome Quick Sort é simples e grosseiro, pois assim que você ouve o nome já sabe o significado de sua existência, que é rápida e eficiente! É um dos algoritmos de classificação mais rápidos para big data. Embora a complexidade de tempo do Pior Caso atinja O(n²), eles são excelentes e, na maioria dos casos, têm desempenho melhor do que algoritmos de ordenação com uma complexidade de tempo média de O(n logn).

O pior caso de execução de classificação rápida é O(n²), como a classificação rápida de matrizes sequenciais. Mas seu tempo esperado amortizado é O(nlogn), e o fator constante implícito na notação O(nlogn) é pequeno, muito menor do que o merge sort cuja complexidade é estável em O(nlogn). Portanto, para a grande maioria das sequências de números aleatórios com ordem mais fraca, a classificação rápida é sempre melhor do que a classificação por mesclagem.

2. Análise do Pensamento

O algoritmo de classificação rápida implementa a classificação por meio de múltiplas comparações e trocas, e seu processo de classificação é o seguinte:
(1) Primeiro, defina um valor de corte e divida a matriz em partes esquerda e direita até o valor de corte.
(2) Colete os dados maiores ou iguais ao valor de corte à direita da matriz e colete os dados menores que o valor de corte à esquerda da matriz. Neste momento, cada elemento na parte esquerda é menor que o valor de corte e cada elemento na parte direita é maior ou igual ao valor de corte.
(3) Em seguida, os dados esquerdo e direito podem ser classificados independentemente. Para os dados da matriz no lado esquerdo, um valor de limite pode ser obtido para dividir essa parte dos dados em partes esquerda e direita, e o valor menor é colocado no lado esquerdo e o valor maior é colocado no lado direito. Os dados da matriz à direita também podem ser processados ​​de forma semelhante.
(4) Repita o processo acima, pode-se ver que esta é uma definição recursiva. Depois de classificar a parte esquerda por recursão, classifique recursivamente a ordem da parte direita. Quando a classificação dos dados nas partes esquerda e direita é concluída, a classificação de toda a matriz também é concluída.

3. Diagrama

3.1 início

Comece de ambas as extremidades da matriz arr, respectivamentedetecção. Primeiro encontre um número menor que 8 da direita para a esquerda, depois encontre um número maior que 8 da esquerda para a direita e depois troque-os. Aqui você pode usar duas variáveis ​​L (esquerda) e R (direita), que apontam para o extremo esquerdo e o extremo direito da sequência, respectivamente. No início, deixe L apontar para a extrema esquerda da matriz, apontando para o número 8. Deixe R apontar para a extrema direita da matriz, apontando para o número 11.
insira a descrição da imagem aqui

3.2 Encontre um número menor que o benchmark da direita para a esquerda

insira a descrição da imagem aqui

3.3 Pare à direita, procure um número maior que o benchmark da esquerda para a direita

insira a descrição da imagem aqui

3.4 Troque os números correspondentes a L e R

insira a descrição da imagem aqui

depois da troca
insira a descrição da imagem aqui

3.5 Continuação do método acima

O primeiro R começa a despachar. Como o número base definido aqui é o número mais à esquerda, é muito importante deixar R ir primeiro (pense por si mesmo por quê). A sentinela R move-se passo a passo para a esquerda (ou seja, R–-) até encontrar um número menor que 8 e parar. Em seguida, a sentinela L move-se passo a passo para a direita (ou seja, L++) até encontrar um número maior que 8 e parar.

intercâmbio
insira a descrição da imagem aqui

depois da troca

insira a descrição da imagem aqui

Neste momento R continua a se mover para a esquerda
insira a descrição da imagem aqui

Então L se move
insira a descrição da imagem aqui

Quando L == R, significa que esta posição é a posição de 8, troque
insira a descrição da imagem aqui

pegar:

insira a descrição da imagem aqui
Isso conclui a primeira rodada de detecção. Neste momento, o número de referência 8 é usado como ponto de divisão, os números à esquerda de 8 são todos menores ou iguais a 8 e os números à direita de 8 são todos maiores ou iguais a 8. Olhando para trás no processo agora, de fato, a missão de R é encontrar um número menor que o número de referência, e a missão de L é encontrar um número maior que o número de referência até que L e R se encontrem.

3.6 Lidando com os números à esquerda

insira a descrição da imagem aqui

3.7 Processando os números à direita

insira a descrição da imagem aqui

pegar:
insira a descrição da imagem aqui

4. Implementação do código

/**
 * 快速排序
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/9/10
 */
public class QuickSort {
    
    
    public static void main(String[] args) {
    
    
        int[] arr = {
    
    8, 12, 19, -1, 45, 0, 14, 4, 11};
        quickSort(arr,0,arr.length-1);
        for (int i = 0; i < arr.length; i++) {
    
    
            System.out.print(arr[i]+" ");
        }
    }
    public static void quickSort(int[] arr,int start, int end){
    
    
        // 什么时候结束排序?
        if (start>end){
    
    
            return;
        }
        // 左指针
        int L = start;
        // 右指针
        int R = end;
        // 基准
        int pivot = arr[start];
        // 只要L!=R就继续循环
        while (L < R){
    
    
            // 右边大于基准,从右向左移动
            while (L<R && arr[R] >= pivot){
    
    
                R --;
            }
            // 左边小于基准,从左向右移动
            while (L<R&& arr[L] <= pivot){
    
    
                L ++;
            }
            // 说明右边有小于基准的数,左边有大于基准的数,交换
            if (L<R){
    
    
                int temp = arr[L];
                arr[L] = arr[R];
                arr[R] = temp;
            }
        }
        // L 与 R碰面 找到了 基准的位置
        arr[start] = arr[L];
        arr[L] = pivot;

        // 左边排序
        quickSort(arr,start,R-1);
        // 右边排序
        quickSort(arr,L+1,end);

    }

}

Classificação rápida Este artigo está bem escrito, você pode consultar a escrita e compreensão da classificação rápida de outras pessoas


classificação de mesclagem

1. Introdução

Merge sort é um algoritmo de classificação eficaz e estável baseado na operação de mesclagem.Este algoritmo é uma aplicação muito típica de dividir e conquistar (Divide and Conquer). Combine as subsequências ordenadas para obter uma sequência completamente ordenada; isto é, primeiro faça cada subsequência em ordem e depois faça os segmentos da subsequência em ordem. Mesclar duas listas classificadas em uma lista classificada é chamado de mesclagem bidirecional.

2. Análise do Pensamento

Merge sort usa a ideia de dividir e conquistar, e a dificuldade é governar

  • Solicite espaço para que seu tamanho seja a soma das duas sequências classificadas, que é usado para armazenar a sequência mesclada
  • em primeiro lugarsequência de decomposição, decompõe a sequência nas sequências em cada grupoA quantidade é 1e, em seguida, execute uma classificação por mesclagem
  • configurardois ponteiros, as posições iniciais são as posições iniciais das duas sequências classificadas
  • Compare os elementos apontados pelos dois ponteiros, selecione o elemento relativamente pequeno e coloque-o no espaço de mesclagem e mova o ponteiro para a próxima posição
  • Repita a etapa anterior até que um determinado ponteiro chegue ao final da sequência
  • Copie todos os elementos restantes de outra sequência diretamente para o final da sequência mesclada

3. Diagrama

3.1 Dividir, decompor todas as sequências

insira a descrição da imagem aqui

3.2 Comece a classificar e mesclar

insira a descrição da imagem aqui

Após cada preenchimento, o ponteiro se move um bit
insira a descrição da imagem aqui

insira a descrição da imagem aqui

Quando a matriz esquerda não possui elementos, a direita é preenchida diretamente
insira a descrição da imagem aqui

pegar
insira a descrição da imagem aqui

4. Implementação do código

/**
 * 归并排序
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/9/12
 */
public class MergeSort {
    
    
    public static void main(String[] args) {
    
    
        int[] arr = {
    
    1, 5, 6, 3, 2, 8, 7, 4};
        int[] temp = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        for (int i = 0; i < arr.length; i++) {
    
    
            System.out.print(arr[i]+" ");
        }
    }

    /** 分解,并合并排序 */
    public static void mergeSort(int[] arr,int left ,int right,int[] temp){
    
    
        if (left<right){
    
    
            //中间索引
            int mid = (left+right)/2;
            //向左递归分解
            mergeSort(arr,left,mid,temp);
            //向右递归分解
            mergeSort(arr,mid+1,right,temp);
            //合并
            merge(arr,left,mid,right,temp);
        }
    }

    /**
     * 合并排序
     * @param arr   未排序的数组
     * @param left  左边有序子数组的初始索引
     * @param mid   中间索引
     * @param right 右边最大索引
     * @param temp  临时数组
     */
    public static void merge(int[] arr,int left,int mid,int right,int[] temp){
    
    
        // 左边指针索引
        int leftPoint = left;
        // 右边指针索引
        int rightPoint = mid+1;
        // 临时数据的指针
        int tempLeft = 0;

        // 两个序列都不为空时
        while (leftPoint <= mid && rightPoint <= right){
    
    
            //如果第一个序列的元素小于第二序列的元素,就将其放入temp中
            if (arr[leftPoint] <= arr[rightPoint]){
    
    
                temp[tempLeft] = arr[leftPoint];
                leftPoint++;
                tempLeft ++;
            }else{
    
    
                temp[tempLeft] = arr[rightPoint];
                rightPoint++;
                tempLeft ++;
            }
        }

        // 右序列为空,直接将做序列的所有元素填充进去
        while (leftPoint <= mid){
    
    
            temp[tempLeft] = arr[leftPoint];
            leftPoint++;
            tempLeft++;
        }

        // 左序列为空,直接将右序列的所有元素填充进去
        while (rightPoint <= right){
    
    
            temp[tempLeft] = arr[rightPoint];
            rightPoint++;
            tempLeft++;
        }

        //将临时数组中的元素放回数组arr中
        tempLeft = 0;
        leftPoint = left;
        while (leftPoint <= right){
    
    
            arr[leftPoint] = temp[tempLeft];
            leftPoint++;
            tempLeft++;
        }


    }
}



classificação radix

1. Introdução

Radix sort (classificação radix) pertence ao "distribution sort", também conhecido como "bucket sort" ou bin sort. Como o nome sugere, ele distribui os elementos a serem classificados por meio de informações parciais de valores-chave para alguns "buckets", em ordem para alcançar o papel de classificação, o método de classificação radix é uma classificação estável e sua complexidade de tempo é O (nlog®m), onde r é a base usada e m é o número de heaps. Em algum ponto, a classificação radix é mais eficiente do que outros tipos de estabilidade.

2. Análise do Pensamento

  • Unifique todos os valores a serem comparados (números inteiros positivos) no mesmo comprimento de dígito e números preenchidos com zeros com dígitos mais curtos
  • Começando pelo bit mais baixo, classifique-os um por um
  • Classificando do dígito mais baixo para o dígito mais alto (dígito de unidades -> dígito de dezenas -> dígito de centenas -> ... -> dígito mais alto) após a classificação ser concluída, a sequência de números torna-se uma sequência ordenada
  • O número de dígitos que precisamos para obter o número máximo
    • Você pode alterar o número máximo para um tipo String e, em seguida, encontrar seu comprimento

3. Diagrama

Primeiro, deve haver 10 baldes representando [0-9]

3.1 A primeira rodada é colocada no balde de acordo com as unidades

insira a descrição da imagem aqui
Em seguida, retire-os um por um. Se houver vários elementos em um balde, aquele que entrar primeiro será retirado primeiro.
insira a descrição da imagem aqui

3.2 A segunda rodada é colocada no balde de acordo com dezenas

insira a descrição da imagem aqui
Se não houver o dígito das dezenas, adicione 0 na frente do dígito das unidades

insira a descrição da imagem aqui

3.3 A terceira rodada é colocada no barril de acordo com a posição das centenas

insira a descrição da imagem aqui

Depois de tirar um por um
insira a descrição da imagem aqui

3.34 A quarta rodada é colocada no balde de acordo com milhares

insira a descrição da imagem aqui

Retire-o para obter:

insira a descrição da imagem aqui

4. Implementação do código


/**
 * 基数排序
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/9/13
 */
public class BaseSorted {
    
    
    public static void main(String[] args) {
    
    
        int[] arr = {
    
    43, 52, 1, 89, 190};
        sort(arr);
        for (int i = 0; i < arr.length; i++) {
    
    
            System.out.print(arr[i] + " ");
        }
    }

    public static void sort(int[] arr){
    
    
        int maxLength = getMaxLength(arr);
        // 定义个二维数组桶,存储元素
        int[][] bucket = new int[10][arr.length];
        // 存储每个桶中有多少个元素
        int[] elementCounts = new int[10];
        for (int times = 1,step = 1; times < maxLength + 1; times++,step *= 10) {
    
    
            // 遍历数组,将元素存入桶中
            for (int i = 0; i < arr.length; i++) {
    
    
                // 获取位数上的数
                int digits = arr[i] / step % 10;
                bucket[digits][elementCounts[digits]] = arr[i];
                elementCounts[digits] ++;
            }

            //将桶中的元素重新放回到数组中
            //用于记录应该放入原数组的哪个位置
            int index = 0;
            for (int i = 0; i < 10; i++) {
    
    
                // 从桶中按放入顺序依次取出元素,放入原数组
                int position = 0;
                while ( elementCounts[i] > 0){
    
    
                    arr[index] = bucket[i][position];
                    position++;
                    elementCounts[i]--;
                    index++;
                }
            }



        }

    }

    /** 获取数组中元素长度最长的长度 */
    public static int getMaxLength(int[] arr){
    
    
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
    
    
            if (arr[i] > max ){
    
    
                max = arr[i];
            }
        }
        return (max + "").length();
    }
}

Acho que você gosta

Origin blog.csdn.net/weixin_46073538/article/details/126802732
Recomendado
Clasificación