Algorithme de tri Java détaillé couramment utilisé (10 types)

Les algorithmes de tri couramment utilisés en Java sont les suivants :

  1. Tri à bulles
  2. Tri de sélection
  3. Tri par insertion
  4. Tri Shell (Tri Shell)
  5. Tri par fusion
  6. Tri rapide (Tri rapide)
  7. Tri par tas
  8. Comptage Trier
  9. Trier par seau
  10. Tri par base (Tri par base)

Ces algorithmes de tri ont leurs propres avantages et inconvénients, et l'algorithme approprié doit être sélectionné en fonction de la situation spécifique.

1. Tri à bulles

Le tri à bulles est un algorithme de tri simple qui parcourt à plusieurs reprises le tableau à trier, en comparant deux éléments à la fois et en échangeant des positions s'ils sont dans le mauvais ordre. Ce processus se poursuit vers la fin de la séquence jusqu'à ce que la séquence entière soit triée.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Bubble {
    
    
    public static void bubbleSort(int[] arr) {
    
    
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
    
    
            for (int j = 0; j < n - i - 1; j++) {
    
    
                if (arr[j] > arr[j + 1]) {
    
    
                    // 交换arr[j+1]和arr[j]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Bubble.bubbleSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction bubbleSort prend un tableau d'entiers en entrée et le trie à l'aide de l'algorithme de tri à bulles. La boucle externe s'exécute n - 1 fois, où n est la longueur du tableau, et la boucle interne s'exécute n - i - 1 fois, où i est le numéro d'itération actuel de la boucle externe. En effet, après chaque itération de la boucle externe, le plus grand élément est définitivement à la fin du tableau, nous n'avons donc pas besoin de le comparer à nouveau.

Dans la boucle interne, nous comparons les éléments adjacents et les échangeons s'ils ne sont pas dans le bon ordre. De cette façon, le plus grand élément "remonte" jusqu'à la fin du tableau. Après chaque passage dans le tableau, le plus grand élément est dans sa position finale, nous pouvons donc réduire la taille de la boucle interne de 1.

La complexité temporelle du tri à bulles est O(n^2), ce qui le rend inefficace pour les grandes listes et les applications pratiques. Cependant, en raison de sa simplicité, c'est un bon algorithme pour enseigner le tri aux débutants.

2. Tri de sélection

Le tri par sélection est un algorithme de tri simple. Son idée de base est de sélectionner à chaque fois l'élément le plus petit (ou le plus grand) parmi les éléments à trier, et de le stocker au début de la séquence jusqu'à ce que tous les éléments à trier soient épuisés.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Selection {
    
    
    public static void selectionSort(int[] arr) {
    
    
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
    
    
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
    
    
                if (arr[j] < arr[minIndex]) {
    
    
                    minIndex = j;
                }
            }
            // 交换arr[i]和arr[minIndex]
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Selection.selectionSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction selectionSort prend un tableau d'entiers en entrée et le trie à l'aide de l'algorithme de tri par sélection. La boucle externe s'exécute n - 1 fois, où n est la longueur du tableau. Dans la boucle interne, nous trouvons le plus petit élément de la partie non triée et stockons son index dans la variable minIndex. Ensuite, nous échangeons le plus petit élément avec la fin de la partie triée. Après chaque itération de boucle externe, la longueur de la partie triée est augmentée de 1 et la longueur de la partie non triée est diminuée de 1.

La complexité temporelle du tri par sélection est O(n^2), ce qui le rend inefficace pour les grandes listes et les applications pratiques. Cependant, en raison de sa simplicité, c'est un bon algorithme pour enseigner le tri aux débutants.

3. Tri par insertion

Le tri par insertion est un algorithme de tri simple dont l'idée de base est d'insérer un enregistrement dans une liste ordonnée déjà triée pour obtenir une nouvelle liste ordonnée avec le nombre d'enregistrements augmenté de 1.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Insertion {
    
    
    public static void insertionSort(int[] arr) {
    
    
        int n = arr.length;
        // 外部循环从第二个元素开始,因为我们将第一个元素视为已排序部分
        for (int i = 1; i < n; i++) {
    
    
            int key = arr[i];
            int j = i - 1;
            // 将当前值key和前面的值进行比较,如果前面的值>key 则将值往后移1位
            while (j >= 0 && arr[j] > key) {
    
    
                arr[j + 1] = arr[j];
                j--;
            }
            // 在不小当前值key的位置,插入当前值key
            arr[j + 1] = key;
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Insertion.insertionSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction insertionSort prend un tableau d'entiers en entrée et le trie à l'aide de l'algorithme de tri par insertion. La boucle externe commence par le deuxième élément, puisque nous considérons le premier élément comme la partie triée. Dans la boucle interne, on compare l'élément à insérer avec l'élément de la partie triée, et si l'élément à insérer est plus petit que l'élément de la partie triée, on décale l'élément de la partie triée d'un bit vers la droite pour faire de la place à l'élément à insérer. Une fois la boucle intérieure terminée, nous insérons l'élément à insérer dans la bonne position. Après chaque itération de boucle externe, nous pouvons nous assurer que les premiers i éléments ont été triés.

Le tri par insertion a une complexité temporelle de O(n^2), ce qui le rend inefficace pour les grandes listes et les applications pratiques. Cependant, le tri par insertion est très simple à mettre en œuvre et fonctionne très bien sur de petites listes.

4. Tri des coques

Le tri Hill est un algorithme de tri par insertion amélioré. Son idée de base est de regrouper le tableau à trier selon un certain intervalle, de trier chaque groupe à l'aide de l'algorithme de tri par insertion, puis de réduire l'intervalle, puis de trier le groupement jusqu'à ce que l'intervalle soit 1.

La méthode de réduction progressive de la taille de l'intervalle contribue à améliorer l'efficacité du processus de tri, ce qui peut réduire le nombre de comparaisons et d'échanges. Il s'agit d'une caractéristique clé de l'algorithme de tri Hill.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Shell {
    
    
    public static void shellSort(int[] arr) {
    
    
        int n = arr.length;
        // 初始化间隔(gap)的值,它决定了每次迭代中子数组的大小
        // 从数组长度的一半开始作为初始间隔值,gap就是分割的子数组数量
        for (int gap = n / 2; gap > 0; gap /= 2) {
    
    
            // 循环从间隔值开始,遍历数组直到数组的末尾;代表循环所有的子数组
            for (int i = gap; i < n; i++) {
    
    
                int temp = arr[i];
                int j = i;
                // 将当前元素 arr[j] 的值替换为前一个元素 arr[j - gap] 的值。
                // 通过这个操作,将较大的元素向后移动,为当前元素腾出位置
                while (j >= gap && arr[j - gap] > temp) {
    
    
                    arr[j] = arr[j - gap];
                    j -= gap;
                }
                arr[j] = temp;
            }
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Shell.shellSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction shellSort prend un tableau d'entiers en entrée et le trie à l'aide de l'algorithme de tri Shell. La boucle externe utilise un écart variable d'intervalle avec une valeur initiale de la moitié de la longueur du tableau et divise l'écart par 2 à chaque fois dans la boucle jusqu'à ce que l'écart soit égal à 1. La boucle interne commence à l'élément gapth, compare l'élément à insérer avec les éléments de la partie triée, et si l'élément à insérer est plus petit que l'élément de la partie triée, déplace les éléments de la partie triée vers la droite par des positions d'écart pour faire de la place pour l'élément à insérer. Une fois la boucle intérieure terminée, nous insérons l'élément à insérer dans la bonne position. Après chaque itération de la boucle externe, nous pouvons nous assurer que les premiers éléments vides du tableau sont triés.

Le tri Hill a une complexité temporelle de O(n^2), mais en pratique, il fonctionne bien mieux que le tri par insertion, en particulier sur les grandes listes. La performance du tri de Hill dépend du choix de la séquence d'espacement, mais il n'existe pas encore de séquence d'espacement optimale.

5. Fusionner le tri

Le tri par fusion est un algorithme de tri diviser pour régner. Son idée de base est de diviser le tableau à trier en plusieurs sous-séquences, chaque sous-séquence est ordonnée, puis de fusionner les sous-séquences en un tableau ordonné.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Merge {
    
    
    public static void mergeSort(int[] arr, int left, int right) {
    
    
        if (left < right) {
    
    
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }
    }

    public static void merge(int[] arr, int left, int mid, int right) {
    
    
        // 子数组 L 的大小
        int n1 = mid - left + 1;
        // 右子数组 R 的大小
        int n2 = right - mid;
        // 创建两个临时数组 L 和 R ,分别用来存储左子数组和右子数组的元素
        int[] L = new int[n1];
        int[] R = new int[n2];
        // 使用 for 循环将原始数组 arr 中的元素复制到临时数组 L 和 R 中,分别从 left 和 mid + 1 开始
        for (int i = 0; i < n1; i++) {
    
    
            L[i] = arr[left + i];
        }
        for (int j = 0; j < n2; j++) {
    
    
            R[j] = arr[mid + 1 + j];
        }
        // 初始化三个变量 i、j和k,分别指向数组 L 、R 和原始数组 arr 的起始位置
        int i = 0, j = 0, k = left;
        // 使用 while 循环,比较 L 和 R 的元素,并将较小的元素放回原始数组 arr 中
        while (i < n1 && j < n2) {
    
    
            if (L[i] <= R[j]) {
    
    
                arr[k] = L[i];
                i++;
            } else {
    
    
                arr[k] = R[j];
                j++;
            }
            k++;
        }
        // 当 L 或 R 中的元素用完时,将剩余的元素依次放回原始数组 arr 中
        while (i < n1) {
    
    
            arr[k] = L[i];
            i++;
            k++;
        }
        while (j < n2) {
    
    
            arr[k] = R[j];
            j++;
            k++;
        }
        // merge 方法执行完毕后,两个子数组范围内的元素已经按照从小到大的顺序合并到了原始数组 arr 中
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Merge.mergeSort(arr, 0, arr.length - 1);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction mergeSort accepte un tableau d'entiers, un index gauche et un index droit en entrée et utilise l'algorithme de tri par fusion pour trier les éléments du tableau dans la plage spécifiée. Cette fonction utilise la récursivité pour diviser le tableau en deux sous-tableaux, puis les trie et enfin les fusionne en un seul tableau trié. La fonction de fusion est utilisée pour fusionner deux tableaux triés en un seul tableau trié. Il crée deux tableaux temporaires L et R, stocke les éléments du sous-tableau gauche dans L et du sous-tableau droit dans R, puis les fusionne en un tableau trié et le stocke dans le tableau d'origine.

La complexité temporelle du tri par fusion est O(nlogn) et ses performances sont bien meilleures que le tri à bulles et le tri par insertion, en particulier sur les grandes listes.

6. Tri rapide

Le tri rapide est un algorithme de tri basé sur l'idée de diviser pour mieux régner. Son idée de base est de séparer les enregistrements à trier en deux parties indépendantes par le biais d'un tri en une passe. Les mots-clés d'une partie des enregistrements sont plus petits que les mots-clés de l'autre partie des enregistrements, puis de continuer à trier les deux parties des enregistrements respectivement, de manière à ordonner la séquence entière.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Quick {
    
    
    // 接收一个数组 arr,一个低索引 low ,和一个高索引 high 作为参数
    public static void quickSort(int[] arr, int low, int high) {
    
    
        // 检查 low 是否小于 high。如果不是,则意味着数组只有一个元素或为空,因此不需要排序
        if (low < high) {
    
    
            int pivot = partition(arr, low, high);
            quickSort(arr, low, pivot - 1);
            quickSort(arr, pivot + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
    
    
        // 将最后一个元素作为枢轴元素( arr[high] )
        int pivot = arr[high];
        // 将 i 初始化为 low - 1,用于跟踪较小元素的索引
        int i = low - 1;
        for (int j = low; j < high; j++) {
    
    
            if (arr[j] < pivot) {
    
    
                // 如果当前元素 arr[j] 小于枢轴元素,则增加 i 并交换 arr[i] 和 arr[j]
                // 较小元素索引+1
                i++;
                // 将当前元素 arr[j] 放在较小元素索引位置
                swap(arr, i, j);
            }
            // 其他情况,则较小元素索引没有增加,说明当前元素应该放在右边
        }
        // 将枢轴元素( arr[high] )与索引 i + 1 处的元素交换。
        // 确保枢轴元素左边是较小元素,右边是较大元素
        swap(arr, i + 1, high);
        // 将 i + 1 作为枢轴索引返回
        return i + 1;
    }

    private static void swap(int[] arr, int i, int j) {
    
    
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 6, 1, 3};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8};
        Quick.quickSort(arr, 0, arr.length - 1);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction quickSort prend un tableau d'entiers, un index bas et un index haut en entrée et utilise l'algorithme de tri rapide pour trier les éléments du tableau dans la plage spécifiée. Cette fonction utilise la récursivité pour diviser le tableau en deux sous-tableaux, puis les trie et enfin les fusionne en un seul tableau trié. La fonction de partition est utilisée pour diviser un tableau en deux sous-tableaux. Il sélectionne le dernier élément du tableau comme élément pivot, puis place les éléments plus petits que l'élément pivot à gauche et les éléments supérieurs à l'élément pivot à droite, et renvoie l'index de l'élément pivot. La fonction swap est utilisée pour échanger deux éléments dans un tableau.

La complexité temporelle du tri rapide est O(nlogn) et ses performances sont bien meilleures que le tri à bulles et le tri par insertion, en particulier sur les grandes listes.

7. Tri par tas

Le tri par tas est un algorithme de tri par sélection arborescente. Son idée de base est de construire le tableau à trier dans un grand tas racine (ou petit tas racine), puis d'échanger la position de l'élément supérieur et de l'élément inférieur du tas, puis de reconstruire les éléments restants en un tas, et de répéter l'opération d'échange et de reconstruction du tas jusqu'à ce que tout le tableau soit en ordre.

Le tri en tas est un algorithme de tri basé sur la structure de données en tas, et sa complexité temporelle est O(nlogn).

notion de tas

L'ensemble K = {k0, k1, k2, ..., kn-1} stocke tous ses éléments dans un tableau à une dimension dans l'ordre d'un arbre binaire complet, et vérifie : Ki <= K2i+1 (nœud de gauche) et Ki<=K2i+2 (nœud de droite), alors on l'appelle un petit tas (ou un grand tas). Le tas avec le plus grand nœud racine est appelé le plus grand tas ou grand tas racine, et le tas avec le plus petit nœud racine est appelé le plus petit tas ou petit tas racine. Arbre binaire complet (sauf pour la dernière couche, les nœuds supérieurs ne sont pas vides et les nœuds de la dernière couche sont disposés de gauche à droite)

La nature du tas

1. La valeur d'un nœud dans le tas n'est toujours ni supérieure ni inférieure à la valeur de son nœud parent ;
2. Le tas est toujours un arbre binaire complet.

public class Heap {
    
    

    public static void heapSort(int[] arr) {
    
    
        int n = arr.length;
        // 构建大根堆
        // 这段代码是构建大根堆的过程,它的循环次数为n/2-1次,是因为在完全二叉树中,叶子节点不需要进行堆化操作,
        // 所以只需要对非叶子节点进行堆化,而非叶子节点的数量为n/2-1个。因此,只需要循环n/2-1次即可完成大根堆的构建。
        // 非叶子节点在一维数组中就是前面 n/2-1
        for (int i = n / 2 - 1; i >= 0; i--) {
    
    
            heapify(arr, n, i);
        }
        // 依次取出堆顶元素,并将余下元素继续堆化,得到有序序列
        for (int i = n - 1; i >= 0; i--) {
    
    
            swap(arr, 0, i);
            heapify(arr, i, 0);
        }
    }

    private static void heapify(int[] arr, int heapSize, int i) {
    
    
        int largest = i; // 初始化最大值为根节点
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        // 找到左右子节点中的最大值
        if (left < heapSize && arr[left] > arr[largest]) {
    
    
            largest = left;
        }
        if (right < heapSize && arr[right] > arr[largest]) {
    
    
            largest = right;
        }
        // 如果最大值不是根节点,则交换根节点与最大值节点,并递归地对最大值节点进行堆化
        if (largest != i) {
    
    
            swap(arr, i, largest);
            heapify(arr, heapSize, largest);
        }
    }

    private static void swap(int[] arr, int i, int j) {
    
    
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 12, 35, 57, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8, 12, 35, 57};
        Heap.heapSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction heapSort prend un tableau d'entiers en entrée et trie le tableau à l'aide de l'algorithme de tri en tas. Cette fonction construit d'abord un grand tas racine, puis extrait les éléments supérieurs du tas à tour de rôle pour obtenir une séquence ordonnée. La fonction heapify est utilisée pour entasser un nœud. Il prend trois paramètres : le tableau à entasser, la taille du tableau et l'index du nœud à entasser. Cette fonction trouve d'abord la valeur maximale parmi les nœuds enfants gauche et droit. Si la valeur maximale n'est pas le nœud racine, alors échangez le nœud racine et le nœud de valeur maximale, et empilez récursivement le nœud de valeur maximale. La fonction swap est utilisée pour échanger deux éléments dans un tableau.

8. Comptage Trier

Le tri par comptage est un algorithme de tri non comparatif. Son idée de base est de compter le nombre d'occurrences de chaque élément dans le tableau, puis de placer les éléments dans un tableau ordonné à tour de rôle en fonction du nombre d'occurrences de l'élément.

La complexité temporelle du tri par comptage est O(n+k), où k est le nombre maximum d'éléments à trier.

import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class Counting {
    
    
    public static void countingSort(int[] arr) {
    
    
        int n = arr.length;
        // 取出数组中最大值
        int max = getMax(arr);
        int[] count = new int[max + 1];
        // 统计每个元素出现的次数
        for (int i = 0; i < n; i++) {
    
    
            count[arr[i]]++;
        }
        // 计算每个元素在有序序列中的位置
        for (int i = 1; i <= max; i++) {
    
    
            // 因为count包含了每个数据出现的次数,所以从小到大,逐个往前加得到就是原数组中每个元素在有序序列中应有的位置
            count[i] += count[i - 1];
        }
        // 输出有序序列
        int[] sortedArr = new int[n];
        for (int i = n - 1; i >= 0; i--) {
    
    
            sortedArr[count[arr[i]] - 1] = arr[i];
            count[arr[i]]--;
        }
        // 将有序序列复制回原数组
        System.arraycopy(sortedArr, 0, arr, 0, n);
    }

    private static int getMax(int[] arr) {
    
    
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
    
    
            if (arr[i] > max) {
    
    
                max = arr[i];
            }
        }
        return max;
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 1, 6, 12};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8, 12};
        Counting.countingSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

9. Trier par seau

Le tri par bucket est un algorithme de tri non comparatif. Son idée de base est de diviser le tableau à trier en un nombre limité de buckets, puis de trier chaque bucket, et enfin de retirer les éléments de tous les buckets à tour de rôle pour former un tableau ordonné.

La complexité temporelle du tri par bucket est O(n), où n est le nombre d'éléments à trier.

import org.junit.jupiter.api.Assertions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Bucket {
    
    
    /**
     * 桶排序
     * @param arr 待排序数组
     * @param bucketSize 桶大小,数据不宜过大,桶越大,后续对桶内数据排序越耗时
     */
    public static void bucketSort(int[] arr, int bucketSize) {
    
    
        if (arr.length == 0) {
    
    
            return;
        }
        // 循环数组,先找到最小值和最大值
        int minValue = arr[0];
        int maxValue = arr[0];
        for (int i = 1; i < arr.length; i++) {
    
    
            if (arr[i] < minValue) {
    
    
                minValue = arr[i];
            } else if (arr[i] > maxValue) {
    
    
                maxValue = arr[i];
            }
        }
        // 根据桶的大小,计算桶个数,并初始化桶
        int bucketCount = (maxValue - minValue) / bucketSize + 1;
        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
    
    
            buckets.add(new ArrayList<>());
        }
        for (int i = 0; i < arr.length; i++) {
    
    
            int bucketIndex = (arr[i] - minValue) / bucketSize;
            buckets.get(bucketIndex).add(arr[i]);
        }
        int currentIndex = 0;
        for (int i = 0; i < bucketCount; i++) {
    
    
            List<Integer> bucket = buckets.get(i);
            // 对桶内数据进行排序
            Collections.sort(bucket);
            // 将数据逐个从桶内取出,并存入数组
            for (int j = 0; j < bucket.size(); j++) {
    
    
                arr[currentIndex++] = bucket.get(j);
            }
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 12, 35, 57, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8, 12, 35, 57};
        Bucket.bucketSort(arr, 20);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction bucketSort prend un tableau d'entiers et la taille du bucket en entrée et trie le tableau à l'aide de l'algorithme de tri du bucket. La fonction trouve d'abord les valeurs minimales et maximales dans le tableau d'entrée et compte le nombre de seaux. Ensuite, la fonction crée une liste de buckets dont la taille est le nombre de buckets pour stocker les éléments dans chaque bucket. Ensuite, la fonction parcourt tour à tour le tableau d'entrée, plaçant chaque élément dans le compartiment correspondant. Ensuite, la fonction trie les éléments dans chaque compartiment et fusionne les éléments triés afin d'obtenir une séquence ordonnée.

10. Tri par base

Le tri par base est un algorithme de tri non comparatif. Son idée de base est de diviser le tableau à trier en fonction du nombre de chiffres (unités, dizaines et centaines), puis de trier les nombres dans chaque chiffre à tour de rôle pour obtenir finalement un tableau ordonné.

La complexité temporelle du tri par base est O(d(n+k)), où d est le nombre de chiffres du plus grand élément, n est le nombre d'éléments à trier et k est le nombre de seaux.

import org.junit.jupiter.api.Assertions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Radix {
    
    
    public static void radixSort(int[] arr) {
    
    
        if (arr.length == 0) {
    
    
            return;
        }
        int maxNum = arr[0];
        for (int i = 1; i < arr.length; i++) {
    
    
            if (arr[i] > maxNum) {
    
    
                maxNum = arr[i];
            }
        }
        int maxDigit = 0;
        while (maxNum != 0) {
    
    
            maxNum /= 10;
            maxDigit++;
        }
        List<List<Integer>> buckets = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
    
    
            buckets.add(new ArrayList<>());
        }
        int mod = 10; // 初始10,用于数据个位数取模
        int div = 1; // 桶序号除数
        // 按位数循环数组,如果数据中有十位数的数据,循环2次,百位数循环3次
        for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
    
    
            // 循环数组,将数据分别存入桶中
            for (int j = 0; j < arr.length; j++) {
    
    
                // 计算当前位数的桶序号
                int bucketIndex = (arr[j] % mod) / div;
                buckets.get(bucketIndex).add(arr[j]);
            }
            // 循环桶列表,将当前位数已排序的数据放入数组中
            int currentIndex = 0;
            for (int j = 0; j < 10; j++) {
    
    
                List<Integer> bucket = buckets.get(j);
                for (int k = 0; k < bucket.size(); k++) {
    
    
                    arr[currentIndex++] = bucket.get(k);
                }
                bucket.clear();
            }
        }
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    5, 2, 8, 3, 12, 35, 57, 1, 6};
        int[] expectedArr = {
    
    1, 2, 3, 5, 6, 8, 12, 35, 57};
        Radix.radixSort(arr);
        System.out.println("arr = " + Arrays.toString(arr));
        Assertions.assertArrayEquals(expectedArr, arr);
    }
}

Dans le code ci-dessus, la fonction radixSort prend un tableau d'entiers en entrée et trie le tableau à l'aide de l'algorithme de tri par base. La fonction trouve d'abord la valeur maximale dans le tableau d'entrée et calcule le nombre de chiffres dans la valeur maximale. La fonction crée ensuite une liste de compartiments de taille 10 pour stocker les éléments dans chaque compartiment. Ensuite, la fonction parcourt tour à tour chaque bit du tableau d'entrée, plaçant chaque élément dans son compartiment correspondant. Ensuite, la fonction combine les éléments de chaque compartiment afin d'obtenir une séquence ordonnée.

Je suppose que tu aimes

Origine blog.csdn.net/wlddhj/article/details/131482951
conseillé
Classement