十大排序算法

1、冒泡排序

简单、两重for循环、两两比较交换位置,持续对数列的末尾进行,直到整个数列都排序完成。

不管序列是怎样,都是要比较n(n-1)/2 次的,最好、最坏、平均时间复杂度都为O(n²),需要一个临时变量用来交换数组内数据位置,所以空间复杂度为O(1)。

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;}}}}
2、选择排序

简单、是冒泡排序的改进版,两重for循环,每次内部循环在未排序元素中选择最小(或最大)元素存放在序列的起始位置。

选择排序无论序列是怎样的都是要比较n(n-1)/2次的,最好、最坏、平均时间复杂度也都为O(n²),需要一个临时变量用来交换数组内数据位置,所以空间复杂度为O(1)。

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;}}
3、插入排序

将一个记录插入到已经排好序的有序表中得到一个新的、记录数+1的有序表。

插入排序,如果序列是完全有序的,插入排序只要比较n次,无需移动,时间复杂度为O(n);如果序列是逆序的,插入排序要比较n²次和移动,所以时间复杂度为O(n²),最好为O(n),最坏为O(n²),平均时间复杂度为O(n²),排序过程中只要一个辅助空间,所以空间复杂度O(1)。

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;}}
4、希尔排序

希尔排序是一种改进的插入排序算法,它的基本思想是将待排序的数组按照一定的间隔进行分组,对每组使用插入排序算法进行排序,然后缩小间隔,再对分组进行排序,直到间隔为1为止。逐渐减小间隔大小的方法有助于提高排序过程的效率,可以减少比较和交换的次数。这是希尔排序算法的一个关键特点

希尔排序的时间复杂度分析及其复杂,只需要记住结论就行,{1,2,4,8,…}这种序列并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n²);{1,3,7,…,2k-1},这种序列的时间复杂度(最坏情形)为O(n1.5);Sedgewick提出了几种增量序列,其最坏情形运行时间为O(n^1.3);其中最好的一个序列是{1,5,19,41,109,…},需要一个临时变量用来交换数组内数据位置,所以空间复杂度为O(1)。

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;}}}
5、快速排序

快速排序是一种分治思想的排序算法,它的基本思想是通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后再分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

快速排序最好情况下时间复杂度是O(nlogn),平均时间复杂度也是O(nlogn),最坏情况是序列本来就是有序的,此时时间复杂度为O(n²),快速排序的空间复杂度可以理解为递归的深度,而递归的实现依靠栈,平均需要递归logn次,所以平均空间复杂度为O(logn)。

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

归并排序是一种分治思想的排序算法,它的基本思想是将待排序的数组分成若干个子序列,每个子序列都是有序的,然后再将子序列合并成一个有序的数组。

归并排序需要一个临时temp[]来储存归并的结果,空间复杂度为O(n),时间复杂度为O(nlogn),可以将空间复杂度由 O(n) 降低至 O(1),然而相对的时间复杂度则由 O(nlogn) 升至 O(n²)。

7、堆排序

堆排序是一种树形选择排序算法,它的基本思想是将待排序的数组构建成一个大根堆(或小根堆),然后将堆顶元素与堆底元素交换位置,再将剩余元素重新构建成堆,重复执行交换和重构堆的操作,直到整个数组有序。

堆排序是一种基于堆数据结构的排序算法,堆排序的平均、最好、最坏时间复杂度都为O(nlogn)。堆排序是就地排序,空间复杂度为常数O(1)。

8、基数排序

基数排序是一种非比较排序算法,它的基本思想是将待排序的数组按照位数(个位、十位、百位)进行划分,然后依次对每个位上的数字进行排序,最终得到有序的数组。

基数排序对于 n 个记录,执行一次分配和收集的时间为O(n+r),如果关键字有 d 位,则要执行 d 遍,所以总的时间复杂度为O(d(n+r))。该算法的空间复杂度就是在分配元素时,使用的桶空间,空间复杂度为O(r+n)=O(n)。

9、桶排序

桶排序是一种非比较排序算法,它的基本思想是将待排序的数组分到有限数量的桶里,然后对每个桶进行排序,最后依次将所有桶中的元素取出来,组成有序的数组。

桶排序的时间复杂度为O(n),其中n为待排序元素的个数。

10、计数排序

计数排序是一种非比较排序算法,它的基本思想是统计数组中每个元素出现的次数,然后根据元素出现的次数依次将元素放入有序的数组中。

计数排序时间复杂度为O(n+k),其中k为待排序的元素的最大值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值